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
|
||||
|
||||
[](http://godoc.org/github.com/go-jet/jet)
|
||||
[](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
|
||||
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
|
||||
|
|
|
|||
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.parent = &column
|
||||
column.subQuery = subQuery
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
//BoolExpression interface
|
||||
type BoolExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -150,6 +151,9 @@ func newBoolExpressionWrap(expression Expression) BoolExpression {
|
|||
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 {
|
||||
return newBoolExpressionWrap(expression)
|
||||
}
|
||||
2
cast.go
2
cast.go
|
|
@ -36,6 +36,8 @@ type castImpl struct {
|
|||
castType string
|
||||
}
|
||||
|
||||
// CAST wraps expression for casting.
|
||||
// For instance: CAST(table.column).AS_BOOL()
|
||||
func CAST(expression Expression) cast {
|
||||
return &castImpl{
|
||||
Expression: expression,
|
||||
|
|
|
|||
23
clause.go
23
clause.go
|
|
@ -40,12 +40,12 @@ type sqlBuilder struct {
|
|||
type statementType string
|
||||
|
||||
const (
|
||||
select_statement statementType = "SELECT"
|
||||
insert_statement statementType = "INSERT"
|
||||
update_statement statementType = "UPDATE"
|
||||
delete_statement statementType = "DELETE"
|
||||
set_statement statementType = "SET"
|
||||
lock_statement statementType = "LOCK"
|
||||
selectStatement statementType = "SELECT"
|
||||
insertStatement statementType = "INSERT"
|
||||
updateStatement statementType = "UPDATE"
|
||||
deleteStatement statementType = "DELETE"
|
||||
setStatement statementType = "SET"
|
||||
lockStatement statementType = "LOCK"
|
||||
)
|
||||
|
||||
const defaultIdent = 5
|
||||
|
|
@ -102,7 +102,7 @@ func (q *sqlBuilder) writeGroupBy(statement statementType, groupBy []groupByClau
|
|||
return err
|
||||
}
|
||||
|
||||
func (q *sqlBuilder) writeOrderBy(statement statementType, orderBy []OrderByClause) error {
|
||||
func (q *sqlBuilder) writeOrderBy(statement statementType, orderBy []orderByClause) error {
|
||||
q.newLine()
|
||||
q.writeString("ORDER BY")
|
||||
|
||||
|
|
@ -189,10 +189,10 @@ func (q *sqlBuilder) finalize() (string, []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)
|
||||
argPlaceholder := "$" + strconv.Itoa(len(q.args))
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ func (q *sqlBuilder) reset() {
|
|||
q.args = []interface{}{}
|
||||
}
|
||||
|
||||
func ArgToString(value interface{}) string {
|
||||
func argToString(value interface{}) string {
|
||||
if isNil(value) {
|
||||
return "NULL"
|
||||
}
|
||||
|
|
@ -213,9 +213,8 @@ func ArgToString(value interface{}) string {
|
|||
case bool:
|
||||
if bindVal {
|
||||
return "TRUE"
|
||||
} else {
|
||||
return "FALSE"
|
||||
}
|
||||
return "FALSE"
|
||||
case int8:
|
||||
return strconv.FormatInt(int64(bindVal), 10)
|
||||
case int:
|
||||
|
|
|
|||
26
column.go
26
column.go
|
|
@ -7,10 +7,11 @@ type column interface {
|
|||
TableName() string
|
||||
|
||||
setTableName(table string)
|
||||
setSubQuery(subQuery ExpressionTable)
|
||||
setSubQuery(subQuery SelectTable)
|
||||
defaultAlias() string
|
||||
}
|
||||
|
||||
// Column is common column interface for all types of columns.
|
||||
type Column interface {
|
||||
Expression
|
||||
column
|
||||
|
|
@ -23,7 +24,7 @@ type columnImpl struct {
|
|||
name string
|
||||
tableName string
|
||||
|
||||
subQuery ExpressionTable
|
||||
subQuery SelectTable
|
||||
}
|
||||
|
||||
func newColumn(name string, tableName string, parent Column) columnImpl {
|
||||
|
|
@ -49,7 +50,7 @@ func (c *columnImpl) setTableName(table string) {
|
|||
c.tableName = table
|
||||
}
|
||||
|
||||
func (c *columnImpl) setSubQuery(subQuery ExpressionTable) {
|
||||
func (c *columnImpl) setSubQuery(subQuery SelectTable) {
|
||||
c.subQuery = subQuery
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ func (c *columnImpl) defaultAlias() string {
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
// projection interface implementation
|
||||
func (cl ColumnList) isProjectionType() {}
|
||||
|
||||
func (cl ColumnList) from(subQuery ExpressionTable) projection {
|
||||
func (cl ColumnList) from(subQuery SelectTable) projection {
|
||||
newProjectionList := ProjectionList{}
|
||||
|
||||
for _, column := range cl {
|
||||
|
|
@ -134,8 +135,11 @@ func (cl ColumnList) serializeForProjection(statement statementType, out *sqlBui
|
|||
|
||||
// dummy column interface implementation
|
||||
|
||||
func (cl ColumnList) Name() string { return "" }
|
||||
func (cl ColumnList) TableName() string { return "" }
|
||||
func (cl ColumnList) setTableName(name string) {}
|
||||
func (cl ColumnList) setSubQuery(subQuery ExpressionTable) {}
|
||||
func (cl ColumnList) defaultAlias() string { return "" }
|
||||
// Name is placeholder for ColumnList to implement Column interface
|
||||
func (cl ColumnList) Name() string { return "" }
|
||||
|
||||
// TableName is placeholder for ColumnList to implement Column interface
|
||||
func (cl ColumnList) TableName() string { return "" }
|
||||
func (cl ColumnList) setTableName(name string) {}
|
||||
func (cl ColumnList) setSubQuery(subQuery SelectTable) {}
|
||||
func (cl ColumnList) defaultAlias() string { return "" }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package jet
|
||||
|
||||
// ColumnBool is interface for SQL boolean columns.
|
||||
type ColumnBool interface {
|
||||
BoolExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnBool
|
||||
From(subQuery SelectTable) ColumnBool
|
||||
}
|
||||
|
||||
type boolColumnImpl struct {
|
||||
|
|
@ -13,7 +14,7 @@ type boolColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *boolColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *boolColumnImpl) from(subQuery SelectTable) projection {
|
||||
newBoolColumn := BoolColumn(i.name)
|
||||
newBoolColumn.setTableName(i.tableName)
|
||||
newBoolColumn.setSubQuery(subQuery)
|
||||
|
|
@ -21,12 +22,13 @@ func (i *boolColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newBoolColumn
|
||||
}
|
||||
|
||||
func (i *boolColumnImpl) From(subQuery ExpressionTable) ColumnBool {
|
||||
func (i *boolColumnImpl) From(subQuery SelectTable) ColumnBool {
|
||||
newBoolColumn := i.from(subQuery).(ColumnBool)
|
||||
|
||||
return newBoolColumn
|
||||
}
|
||||
|
||||
// BoolColumn creates named bool column.
|
||||
func BoolColumn(name string) ColumnBool {
|
||||
boolColumn := &boolColumnImpl{}
|
||||
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 {
|
||||
FloatExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnFloat
|
||||
From(subQuery SelectTable) ColumnFloat
|
||||
}
|
||||
|
||||
type floatColumnImpl struct {
|
||||
|
|
@ -49,7 +52,7 @@ type floatColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *floatColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *floatColumnImpl) from(subQuery SelectTable) projection {
|
||||
newFloatColumn := FloatColumn(i.name)
|
||||
newFloatColumn.setTableName(i.tableName)
|
||||
newFloatColumn.setSubQuery(subQuery)
|
||||
|
|
@ -57,12 +60,13 @@ func (i *floatColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newFloatColumn
|
||||
}
|
||||
|
||||
func (i *floatColumnImpl) From(subQuery ExpressionTable) ColumnFloat {
|
||||
func (i *floatColumnImpl) From(subQuery SelectTable) ColumnFloat {
|
||||
newFloatColumn := i.from(subQuery).(ColumnFloat)
|
||||
|
||||
return newFloatColumn
|
||||
}
|
||||
|
||||
// FloatColumn creates named float column.
|
||||
func FloatColumn(name string) ColumnFloat {
|
||||
floatColumn := &floatColumnImpl{}
|
||||
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 {
|
||||
IntegerExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnInteger
|
||||
From(subQuery SelectTable) ColumnInteger
|
||||
}
|
||||
|
||||
type integerColumnImpl struct {
|
||||
|
|
@ -86,7 +91,7 @@ type integerColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *integerColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *integerColumnImpl) from(subQuery SelectTable) projection {
|
||||
newIntColumn := IntegerColumn(i.name)
|
||||
newIntColumn.setTableName(i.tableName)
|
||||
newIntColumn.setSubQuery(subQuery)
|
||||
|
|
@ -94,10 +99,11 @@ func (i *integerColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newIntColumn
|
||||
}
|
||||
|
||||
func (i *integerColumnImpl) From(subQuery ExpressionTable) ColumnInteger {
|
||||
func (i *integerColumnImpl) From(subQuery SelectTable) ColumnInteger {
|
||||
return i.from(subQuery).(ColumnInteger)
|
||||
}
|
||||
|
||||
// IntegerColumn creates named integer column.
|
||||
func IntegerColumn(name string) ColumnInteger {
|
||||
integerColumn := &integerColumnImpl{}
|
||||
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 {
|
||||
StringExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnString
|
||||
From(subQuery SelectTable) ColumnString
|
||||
}
|
||||
|
||||
type stringColumnImpl struct {
|
||||
|
|
@ -121,7 +129,7 @@ type stringColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *stringColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *stringColumnImpl) from(subQuery SelectTable) projection {
|
||||
newStrColumn := StringColumn(i.name)
|
||||
newStrColumn.setTableName(i.tableName)
|
||||
newStrColumn.setSubQuery(subQuery)
|
||||
|
|
@ -129,10 +137,11 @@ func (i *stringColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newStrColumn
|
||||
}
|
||||
|
||||
func (i *stringColumnImpl) From(subQuery ExpressionTable) ColumnString {
|
||||
func (i *stringColumnImpl) From(subQuery SelectTable) ColumnString {
|
||||
return i.from(subQuery).(ColumnString)
|
||||
}
|
||||
|
||||
// StringColumn creates named string column.
|
||||
func StringColumn(name string) ColumnString {
|
||||
stringColumn := &stringColumnImpl{}
|
||||
stringColumn.stringInterfaceImpl.parent = stringColumn
|
||||
|
|
@ -143,11 +152,12 @@ func StringColumn(name string) ColumnString {
|
|||
|
||||
//------------------------------------------------------//
|
||||
|
||||
// ColumnTime is interface for SQL time column.
|
||||
type ColumnTime interface {
|
||||
TimeExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnTime
|
||||
From(subQuery SelectTable) ColumnTime
|
||||
}
|
||||
|
||||
type timeColumnImpl struct {
|
||||
|
|
@ -155,7 +165,7 @@ type timeColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *timeColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *timeColumnImpl) from(subQuery SelectTable) projection {
|
||||
newTimeColumn := TimeColumn(i.name)
|
||||
newTimeColumn.setTableName(i.tableName)
|
||||
newTimeColumn.setSubQuery(subQuery)
|
||||
|
|
@ -163,10 +173,11 @@ func (i *timeColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newTimeColumn
|
||||
}
|
||||
|
||||
func (i *timeColumnImpl) From(subQuery ExpressionTable) ColumnTime {
|
||||
func (i *timeColumnImpl) From(subQuery SelectTable) ColumnTime {
|
||||
return i.from(subQuery).(ColumnTime)
|
||||
}
|
||||
|
||||
// TimeColumn creates named time column
|
||||
func TimeColumn(name string) ColumnTime {
|
||||
timeColumn := &timeColumnImpl{}
|
||||
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 {
|
||||
TimezExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnTimez
|
||||
From(subQuery SelectTable) ColumnTimez
|
||||
}
|
||||
|
||||
type timezColumnImpl struct {
|
||||
|
|
@ -189,7 +201,7 @@ type timezColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *timezColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *timezColumnImpl) from(subQuery SelectTable) projection {
|
||||
newTimezColumn := TimezColumn(i.name)
|
||||
newTimezColumn.setTableName(i.tableName)
|
||||
newTimezColumn.setSubQuery(subQuery)
|
||||
|
|
@ -197,10 +209,11 @@ func (i *timezColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newTimezColumn
|
||||
}
|
||||
|
||||
func (i *timezColumnImpl) From(subQuery ExpressionTable) ColumnTimez {
|
||||
func (i *timezColumnImpl) From(subQuery SelectTable) ColumnTimez {
|
||||
return i.from(subQuery).(ColumnTimez)
|
||||
}
|
||||
|
||||
// TimezColumn creates named time with time zone column.
|
||||
func TimezColumn(name string) ColumnTimez {
|
||||
timezColumn := &timezColumnImpl{}
|
||||
timezColumn.timezInterfaceImpl.parent = timezColumn
|
||||
|
|
@ -211,11 +224,12 @@ func TimezColumn(name string) ColumnTimez {
|
|||
|
||||
//------------------------------------------------------//
|
||||
|
||||
// ColumnTimestamp is interface of SQL timestamp columns.
|
||||
type ColumnTimestamp interface {
|
||||
TimestampExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnTimestamp
|
||||
From(subQuery SelectTable) ColumnTimestamp
|
||||
}
|
||||
|
||||
type timestampColumnImpl struct {
|
||||
|
|
@ -224,7 +238,7 @@ type timestampColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *timestampColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *timestampColumnImpl) from(subQuery SelectTable) projection {
|
||||
newTimestampColumn := TimestampColumn(i.name)
|
||||
newTimestampColumn.setTableName(i.tableName)
|
||||
newTimestampColumn.setSubQuery(subQuery)
|
||||
|
|
@ -232,10 +246,11 @@ func (i *timestampColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newTimestampColumn
|
||||
}
|
||||
|
||||
func (i *timestampColumnImpl) From(subQuery ExpressionTable) ColumnTimestamp {
|
||||
func (i *timestampColumnImpl) From(subQuery SelectTable) ColumnTimestamp {
|
||||
return i.from(subQuery).(ColumnTimestamp)
|
||||
}
|
||||
|
||||
// TimestampColumn creates named timestamp column
|
||||
func TimestampColumn(name string) ColumnTimestamp {
|
||||
timestampColumn := ×tampColumnImpl{}
|
||||
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 {
|
||||
TimestampzExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnTimestampz
|
||||
From(subQuery SelectTable) ColumnTimestampz
|
||||
}
|
||||
|
||||
type timestampzColumnImpl struct {
|
||||
|
|
@ -259,7 +275,7 @@ type timestampzColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *timestampzColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *timestampzColumnImpl) from(subQuery SelectTable) projection {
|
||||
newTimestampzColumn := TimestampzColumn(i.name)
|
||||
newTimestampzColumn.setTableName(i.tableName)
|
||||
newTimestampzColumn.setSubQuery(subQuery)
|
||||
|
|
@ -267,10 +283,11 @@ func (i *timestampzColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newTimestampzColumn
|
||||
}
|
||||
|
||||
func (i *timestampzColumnImpl) From(subQuery ExpressionTable) ColumnTimestampz {
|
||||
func (i *timestampzColumnImpl) From(subQuery SelectTable) ColumnTimestampz {
|
||||
return i.from(subQuery).(ColumnTimestampz)
|
||||
}
|
||||
|
||||
// TimestampzColumn creates named timestamp with time zone column.
|
||||
func TimestampzColumn(name string) ColumnTimestampz {
|
||||
timestampzColumn := ×tampzColumnImpl{}
|
||||
timestampzColumn.timestampzInterfaceImpl.parent = timestampzColumn
|
||||
|
|
@ -281,11 +298,12 @@ func TimestampzColumn(name string) ColumnTimestampz {
|
|||
|
||||
//------------------------------------------------------//
|
||||
|
||||
// ColumnDate is interface of SQL date columns.
|
||||
type ColumnDate interface {
|
||||
DateExpression
|
||||
column
|
||||
|
||||
From(subQuery ExpressionTable) ColumnDate
|
||||
From(subQuery SelectTable) ColumnDate
|
||||
}
|
||||
|
||||
type dateColumnImpl struct {
|
||||
|
|
@ -294,7 +312,7 @@ type dateColumnImpl struct {
|
|||
columnImpl
|
||||
}
|
||||
|
||||
func (i *dateColumnImpl) from(subQuery ExpressionTable) projection {
|
||||
func (i *dateColumnImpl) from(subQuery SelectTable) projection {
|
||||
newDateColumn := DateColumn(i.name)
|
||||
newDateColumn.setTableName(i.tableName)
|
||||
newDateColumn.setSubQuery(subQuery)
|
||||
|
|
@ -302,10 +320,11 @@ func (i *dateColumnImpl) from(subQuery ExpressionTable) projection {
|
|||
return newDateColumn
|
||||
}
|
||||
|
||||
func (i *dateColumnImpl) From(subQuery ExpressionTable) ColumnDate {
|
||||
func (i *dateColumnImpl) From(subQuery SelectTable) ColumnDate {
|
||||
return i.from(subQuery).(ColumnDate)
|
||||
}
|
||||
|
||||
// DateColumn creates named date column.
|
||||
func DateColumn(name string) ColumnDate {
|
||||
dateColumn := &dateColumnImpl{}
|
||||
dateColumn.dateInterfaceImpl.parent = dateColumn
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// DateExpression is interface for all SQL date expressions.
|
||||
type DateExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -63,6 +64,9 @@ func newDateExpressionWrap(expression Expression) DateExpression {
|
|||
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 {
|
||||
return newDateExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/go-jet/jet/execution"
|
||||
)
|
||||
|
||||
// DeleteStatement is interface for SQL DELETE statement
|
||||
type DeleteStatement interface {
|
||||
Statement
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
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
|
||||
}
|
||||
|
||||
|
|
@ -56,11 +57,11 @@ func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
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
|
||||
}
|
||||
|
||||
if err := out.writeReturning(delete_statement, d.returning); err != nil {
|
||||
if err := out.writeReturning(deleteStatement, d.returning); err != nil {
|
||||
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 {
|
||||
return queryContext(d, db, context, destination)
|
||||
return queryContext(context, d, db, destination)
|
||||
}
|
||||
|
||||
func (d *deleteStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||
|
|
|
|||
4
doc.go
4
doc.go
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
package jet
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ type enumValue struct {
|
|||
name string
|
||||
}
|
||||
|
||||
// NewEnumValue creates new named enum value
|
||||
func NewEnumValue(name string) StringExpression {
|
||||
enumValue := &enumValue{name: name}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ import (
|
|||
"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 {
|
||||
clause
|
||||
projection
|
||||
groupByClause
|
||||
OrderByClause
|
||||
orderByClause
|
||||
|
||||
// Test expression whether it is a NULL value.
|
||||
IS_NULL() BoolExpression
|
||||
|
|
@ -25,16 +26,16 @@ type Expression interface {
|
|||
AS(alias string) projection
|
||||
|
||||
// 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
|
||||
DESC() OrderByClause
|
||||
DESC() orderByClause
|
||||
}
|
||||
|
||||
type expressionInterfaceImpl struct {
|
||||
parent Expression
|
||||
}
|
||||
|
||||
func (e *expressionInterfaceImpl) from(subQuery ExpressionTable) projection {
|
||||
func (e *expressionInterfaceImpl) from(subQuery SelectTable) projection {
|
||||
return e.parent
|
||||
}
|
||||
|
||||
|
|
@ -58,11 +59,11 @@ func (e *expressionInterfaceImpl) AS(alias string) projection {
|
|||
return newAlias(e.parent, alias)
|
||||
}
|
||||
|
||||
func (e *expressionInterfaceImpl) ASC() OrderByClause {
|
||||
func (e *expressionInterfaceImpl) ASC() orderByClause {
|
||||
return newOrderByClause(e.parent, true)
|
||||
}
|
||||
|
||||
func (e *expressionInterfaceImpl) DESC() OrderByClause {
|
||||
func (e *expressionInterfaceImpl) DESC() orderByClause {
|
||||
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 {
|
||||
if p == nil {
|
||||
return errors.New("jet: Prefix Expression is nil.")
|
||||
return errors.New("jet: Prefix Expression is nil")
|
||||
}
|
||||
|
||||
out.writeString(p.operator + " ")
|
||||
|
||||
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 {
|
||||
return err
|
||||
|
|
@ -177,11 +178,11 @@ func newPostfixOpExpression(expression Expression, operator string) postfixOpExp
|
|||
|
||||
func (p *postfixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
||||
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 {
|
||||
return errors.New("jet: nil prefix Expression.")
|
||||
return errors.New("jet: nil prefix Expression")
|
||||
}
|
||||
if err := p.expression.serialize(statement, out); err != nil {
|
||||
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
|
||||
|
||||
//FloatExpression is interface for SQL float columns
|
||||
type FloatExpression interface {
|
||||
Expression
|
||||
numericExpression
|
||||
|
|
@ -115,6 +116,9 @@ func newFloatExpressionWrap(expression Expression) FloatExpression {
|
|||
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 {
|
||||
return newFloatExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,466 @@ package jet
|
|||
|
||||
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 {
|
||||
expressionInterfaceImpl
|
||||
|
||||
|
|
@ -175,375 +635,3 @@ func newTimestampzFunc(name string, expressions ...Expression) *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
|
||||
|
||||
import (
|
||||
"gotest.tools/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -156,14 +155,3 @@ func TestFuncLEAST(t *testing.T) {
|
|||
assertClauseSerialize(t, LEAST(table1ColFloat), "LEAST(table1.col_float)")
|
||||
assertClauseSerialize(t, LEAST(Float(11.2222), NULL, String("str")), "LEAST($1, NULL, $2)", float64(11.2222), "str")
|
||||
}
|
||||
|
||||
func 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"
|
||||
)
|
||||
|
||||
// InsertStatement is interface for SQL INSERT statements
|
||||
type InsertStatement interface {
|
||||
Statement
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
|||
return "", nil, errors.New("jet: table is nil")
|
||||
}
|
||||
|
||||
err = i.table.serialize(insert_statement, queryData)
|
||||
err = i.table.serialize(insertStatement, queryData)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -114,8 +115,8 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
|||
if len(i.rows) > 0 {
|
||||
queryData.writeString("VALUES")
|
||||
|
||||
for row_i, row := range i.rows {
|
||||
if row_i > 0 {
|
||||
for rowIndex, row := range i.rows {
|
||||
if rowIndex > 0 {
|
||||
queryData.writeString(",")
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +124,7 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
|||
queryData.newLine()
|
||||
queryData.writeString("(")
|
||||
|
||||
err = serializeClauseList(insert_statement, row, queryData)
|
||||
err = serializeClauseList(insertStatement, row, queryData)
|
||||
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
|
|
@ -135,14 +136,14 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
|||
}
|
||||
|
||||
if i.query != nil {
|
||||
err = i.query.serialize(insert_statement, queryData)
|
||||
err = i.query.serialize(insertStatement, queryData)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = queryData.writeReturning(insert_statement, i.returning); err != nil {
|
||||
if err = queryData.writeReturning(insertStatement, i.returning); err != nil {
|
||||
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 {
|
||||
return queryContext(i, db, context, destination)
|
||||
return queryContext(context, i, db, destination)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||
($1, $2),
|
||||
($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) {
|
||||
|
|
@ -125,23 +125,23 @@ func TestInsertQuery(t *testing.T) {
|
|||
stmt := table1.INSERT(table1Col1).
|
||||
QUERY(table1.SELECT(table1Col1))
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
INSERT INTO db.table1 (col1) (
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
);
|
||||
`
|
||||
assertStatement(t, stmt, expectedSql)
|
||||
assertStatement(t, stmt, expectedSQL)
|
||||
}
|
||||
|
||||
func TestInsertDefaultValue(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
VALUES(DEFAULT, "two")
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||
(DEFAULT, $1);
|
||||
`
|
||||
|
||||
assertStatement(t, stmt, expectedSql, "two")
|
||||
assertStatement(t, stmt, expectedSQL, "two")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// IntegerExpression interface
|
||||
type IntegerExpression interface {
|
||||
Expression
|
||||
numericExpression
|
||||
|
|
@ -180,6 +181,9 @@ func newIntExpressionWrap(expression Expression) IntegerExpression {
|
|||
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 {
|
||||
return newIntExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package jet
|
||||
|
||||
const (
|
||||
// DEFAULT is jet equivalent of SQL DEFAULT
|
||||
DEFAULT keywordClause = "DEFAULT"
|
||||
)
|
||||
|
||||
var (
|
||||
// NULL is jet equivalent of SQL NULL
|
||||
NULL = newNullLiteral()
|
||||
// STAR is jet equivalent of SQL *
|
||||
STAR = newStarLiteral()
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ func (l literalExpression) serialize(statement statementType, out *sqlBuilder, o
|
|||
if l.constant {
|
||||
out.insertConstantArgument(l.value)
|
||||
} else {
|
||||
out.insertPreparedArgument(l.value)
|
||||
out.insertParametrizedArgument(l.value)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -38,6 +38,7 @@ type integerLiteralExpression struct {
|
|||
integerInterfaceImpl
|
||||
}
|
||||
|
||||
// Int is constructor for integer expressions literals.
|
||||
func Int(value int64) IntegerExpression {
|
||||
numLiteral := &integerLiteralExpression{}
|
||||
|
||||
|
|
@ -55,6 +56,7 @@ type boolLiteralExpression struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
// Bool creates new bool literal expression
|
||||
func Bool(value bool) BoolExpression {
|
||||
boolLiteralExpression := boolLiteralExpression{}
|
||||
|
||||
|
|
@ -70,6 +72,7 @@ type floatLiteral struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
// Float creates new float literal expression
|
||||
func Float(value float64) FloatExpression {
|
||||
floatLiteral := floatLiteral{}
|
||||
floatLiteral.literalExpression = *literal(value)
|
||||
|
|
@ -85,6 +88,7 @@ type stringLiteral struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
// String creates new string literal expression
|
||||
func String(value string) StringExpression {
|
||||
stringLiteral := stringLiteral{}
|
||||
stringLiteral.literalExpression = *literal(value)
|
||||
|
|
@ -100,6 +104,7 @@ type timeLiteral struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
// Time creates new time literal expression
|
||||
func Time(hour, minute, second, milliseconds int) TimeExpression {
|
||||
timeLiteral := &timeLiteral{}
|
||||
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d", hour, minute, second, milliseconds)
|
||||
|
|
@ -116,6 +121,7 @@ type timezLiteral struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
// Timez creates new time with time zone literal expression
|
||||
func Timez(hour, minute, second, milliseconds, timezone int) TimezExpression {
|
||||
timezLiteral := &timezLiteral{}
|
||||
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d %+03d", hour, minute, second, milliseconds, timezone)
|
||||
|
|
@ -132,6 +138,7 @@ type timestampLiteral struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
// Timestamp creates new timestamp literal expression
|
||||
func Timestamp(year, month, day, hour, minute, second, milliseconds int) TimestampExpression {
|
||||
timestampLiteral := ×tampLiteral{}
|
||||
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
|
||||
}
|
||||
|
||||
// Timestampz creates new timestamp with time zone literal expression
|
||||
func Timestampz(year, month, day, hour, minute, second, milliseconds, timezone int) TimestampzExpression {
|
||||
timestampzLiteral := ×tampzLiteral{}
|
||||
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d %+04d",
|
||||
|
|
@ -166,6 +174,7 @@ type dateLiteral struct {
|
|||
literalExpression
|
||||
}
|
||||
|
||||
//Date creates new date expression
|
||||
func Date(year, month, day int) DateExpression {
|
||||
dateLiteral := &dateLiteral{}
|
||||
|
||||
|
|
@ -226,6 +235,7 @@ func (n *wrap) serialize(statement statementType, out *sqlBuilder, options ...se
|
|||
return err
|
||||
}
|
||||
|
||||
// WRAP wraps list of expressions with brackets '(' and ')'
|
||||
func WRAP(expression ...Expression) Expression {
|
||||
wrap := &wrap{expressions: expression}
|
||||
wrap.expressionInterfaceImpl.parent = wrap
|
||||
|
|
@ -245,6 +255,8 @@ func (n *rawExpression) serialize(statement statementType, out *sqlBuilder, opti
|
|||
return nil
|
||||
}
|
||||
|
||||
// RAW can be used for any unsupported functions, operators or expressions.
|
||||
// For example: RAW("current_database()")
|
||||
func RAW(raw string) Expression {
|
||||
rawExp := &rawExpression{raw: raw}
|
||||
rawExp.expressionInterfaceImpl.parent = rawExp
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ import (
|
|||
"github.com/go-jet/jet/execution"
|
||||
)
|
||||
|
||||
// TableLockMode is a type of possible SQL table lock
|
||||
type TableLockMode string
|
||||
|
||||
// Lock types for LockStatement.
|
||||
const (
|
||||
LOCK_ACCESS_SHARE = "ACCESS SHARE"
|
||||
LOCK_ROW_SHARE = "ROW SHARE"
|
||||
|
|
@ -20,6 +22,7 @@ const (
|
|||
LOCK_ACCESS_EXCLUSIVE = "ACCESS EXCLUSIVE"
|
||||
)
|
||||
|
||||
// LockStatement interface for SQL LOCK statement
|
||||
type LockStatement interface {
|
||||
Statement
|
||||
|
||||
|
|
@ -33,6 +36,7 @@ type lockStatementImpl struct {
|
|||
nowait bool
|
||||
}
|
||||
|
||||
// LOCK creates lock statement for list of tables.
|
||||
func LOCK(tables ...WritableTable) LockStatement {
|
||||
return &lockStatementImpl{
|
||||
tables: tables,
|
||||
|
|
@ -55,11 +59,11 @@ func (l *lockStatementImpl) DebugSql() (query string, err error) {
|
|||
|
||||
func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) {
|
||||
if l == nil {
|
||||
return "", nil, errors.New("jet: nil Statement.")
|
||||
return "", nil, errors.New("jet: nil Statement")
|
||||
}
|
||||
|
||||
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{}
|
||||
|
|
@ -72,7 +76,7 @@ func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error)
|
|||
out.writeString(", ")
|
||||
}
|
||||
|
||||
err := table.serialize(lock_statement, out)
|
||||
err := table.serialize(lockStatement, out)
|
||||
|
||||
if err != nil {
|
||||
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 {
|
||||
return queryContext(l, db, context, destination)
|
||||
return queryContext(context, l, db, destination)
|
||||
}
|
||||
|
||||
func (l *lockStatementImpl) Exec(db execution.DB) (sql.Result, error) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// NumericExpression is common interface for all integer and float expressions
|
||||
type NumericExpression interface {
|
||||
Expression
|
||||
numericExpression
|
||||
|
|
|
|||
22
operators.go
22
operators.go
|
|
@ -4,17 +4,19 @@ import "errors"
|
|||
|
||||
//----------- Logical operators ---------------//
|
||||
|
||||
// Returns negation of bool expression expr
|
||||
// NOT returns negation of bool expression result
|
||||
func NOT(exp BoolExpression) BoolExpression {
|
||||
return newPrefixBoolOperator(exp, "NOT")
|
||||
}
|
||||
|
||||
// BIT_NOT inverts every bit in integer expression result
|
||||
func BIT_NOT(expr IntegerExpression) IntegerExpression {
|
||||
return newPrefixIntegerOperator(expr, "~")
|
||||
}
|
||||
|
||||
//----------- Comparison operators ---------------//
|
||||
|
||||
// EXISTS checks for existence of the rows in subQuery
|
||||
func EXISTS(subQuery SelectStatement) BoolExpression {
|
||||
return newPrefixBoolOperator(subQuery, "EXISTS")
|
||||
}
|
||||
|
|
@ -59,12 +61,13 @@ func gtEq(lhs, rhs Expression) BoolExpression {
|
|||
|
||||
// --------------- CASE operator -------------------//
|
||||
|
||||
type CaseOperatorExpression interface {
|
||||
// CaseOperator is interface for SQL case operator
|
||||
type CaseOperator interface {
|
||||
Expression
|
||||
|
||||
WHEN(condition Expression) CaseOperatorExpression
|
||||
THEN(then Expression) CaseOperatorExpression
|
||||
ELSE(els Expression) CaseOperatorExpression
|
||||
WHEN(condition Expression) CaseOperator
|
||||
THEN(then Expression) CaseOperator
|
||||
ELSE(els Expression) CaseOperator
|
||||
}
|
||||
|
||||
type caseOperatorImpl struct {
|
||||
|
|
@ -76,7 +79,8 @@ type caseOperatorImpl struct {
|
|||
els Expression
|
||||
}
|
||||
|
||||
func CASE(expression ...Expression) CaseOperatorExpression {
|
||||
// CASE create CASE operator with optional list of expressions
|
||||
func CASE(expression ...Expression) CaseOperator {
|
||||
caseExp := &caseOperatorImpl{}
|
||||
|
||||
if len(expression) > 0 {
|
||||
|
|
@ -88,17 +92,17 @@ func CASE(expression ...Expression) CaseOperatorExpression {
|
|||
return caseExp
|
||||
}
|
||||
|
||||
func (c *caseOperatorImpl) WHEN(when Expression) CaseOperatorExpression {
|
||||
func (c *caseOperatorImpl) WHEN(when Expression) CaseOperator {
|
||||
c.when = append(c.when, when)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *caseOperatorImpl) THEN(then Expression) CaseOperatorExpression {
|
||||
func (c *caseOperatorImpl) THEN(then Expression) CaseOperator {
|
||||
c.then = append(c.then, then)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *caseOperatorImpl) ELSE(els Expression) CaseOperatorExpression {
|
||||
func (c *caseOperatorImpl) ELSE(els Expression) CaseOperator {
|
||||
c.els = els
|
||||
|
||||
return c
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import "testing"
|
|||
func TestOperatorNOT(t *testing.T) {
|
||||
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))
|
||||
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))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ package jet
|
|||
|
||||
import "errors"
|
||||
|
||||
type OrderByClause interface {
|
||||
// OrderByClause
|
||||
type orderByClause interface {
|
||||
serializeForOrderBy(statement statementType, out *sqlBuilder) error
|
||||
}
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ type orderByClauseImpl struct {
|
|||
|
||||
func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error {
|
||||
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 {
|
||||
|
|
@ -29,6 +30,6 @@ func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sq
|
|||
return nil
|
||||
}
|
||||
|
||||
func newOrderByClause(expression Expression, ascent bool) OrderByClause {
|
||||
func newOrderByClause(expression Expression, ascent bool) orderByClause {
|
||||
return &orderByClauseImpl{expression: expression, ascent: ascent}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@ package jet
|
|||
|
||||
type projection interface {
|
||||
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
|
||||
|
||||
func (cl ProjectionList) from(subQuery ExpressionTable) projection {
|
||||
func (cl ProjectionList) from(subQuery SelectTable) projection {
|
||||
newProjectionList := ProjectionList{}
|
||||
|
||||
for _, projection := range cl {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/go-jet/jet/execution"
|
||||
)
|
||||
|
||||
// Select statements lock types
|
||||
var (
|
||||
UPDATE = newLock("UPDATE")
|
||||
NO_KEY_UPDATE = newLock("NO KEY UPDATE")
|
||||
|
|
@ -14,6 +15,7 @@ var (
|
|||
KEY_SHARE = newLock("KEY SHARE")
|
||||
)
|
||||
|
||||
// SelectStatement is interface for SQL SELECT statements
|
||||
type SelectStatement interface {
|
||||
Statement
|
||||
Expression
|
||||
|
|
@ -23,7 +25,7 @@ type SelectStatement interface {
|
|||
WHERE(expression BoolExpression) SelectStatement
|
||||
GROUP_BY(groupByClauses ...groupByClause) SelectStatement
|
||||
HAVING(boolExpression BoolExpression) SelectStatement
|
||||
ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
|
||||
ORDER_BY(orderByClauses ...orderByClause) SelectStatement
|
||||
LIMIT(limit int64) SelectStatement
|
||||
OFFSET(offset int64) SelectStatement
|
||||
FOR(lock SelectLock) SelectStatement
|
||||
|
|
@ -35,11 +37,12 @@ type SelectStatement interface {
|
|||
EXCEPT(rhs SelectStatement) SelectStatement
|
||||
EXCEPT_ALL(rhs SelectStatement) SelectStatement
|
||||
|
||||
AsTable(alias string) ExpressionTable
|
||||
AsTable(alias string) SelectTable
|
||||
|
||||
projections() []projection
|
||||
}
|
||||
|
||||
//SELECT creates new SelectStatement with list of projections
|
||||
func SELECT(projection1 projection, projections ...projection) SelectStatement {
|
||||
return newSelectStatement(nil, append([]projection{projection1}, projections...))
|
||||
}
|
||||
|
|
@ -55,7 +58,7 @@ type selectStatementImpl struct {
|
|||
groupBy []groupByClause
|
||||
having BoolExpression
|
||||
|
||||
orderBy []OrderByClause
|
||||
orderBy []orderByClause
|
||||
limit, offset int64
|
||||
|
||||
lockFor SelectLock
|
||||
|
|
@ -81,8 +84,8 @@ func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
|
|||
return s.parent
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) AsTable(alias string) ExpressionTable {
|
||||
return newExpressionTable(s.parent, alias, s.parent.projections())
|
||||
func (s *selectStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s.parent, alias)
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) WHERE(expression BoolExpression) SelectStatement {
|
||||
|
|
@ -100,7 +103,7 @@ func (s *selectStatementImpl) HAVING(expression BoolExpression) SelectStatement
|
|||
return s.parent
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) ORDER_BY(clauses ...OrderByClause) SelectStatement {
|
||||
func (s *selectStatementImpl) ORDER_BY(clauses ...orderByClause) SelectStatement {
|
||||
s.orderBy = clauses
|
||||
return s.parent
|
||||
}
|
||||
|
|
@ -189,20 +192,20 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if s.where != nil {
|
||||
err := out.writeWhere(select_statement, s.where)
|
||||
err := out.writeWhere(selectStatement, s.where)
|
||||
|
||||
if err != nil {
|
||||
return nil
|
||||
|
|
@ -210,7 +213,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
}
|
||||
|
||||
if s.groupBy != nil && len(s.groupBy) > 0 {
|
||||
err := out.writeGroupBy(select_statement, s.groupBy)
|
||||
err := out.writeGroupBy(selectStatement, s.groupBy)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -218,7 +221,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
}
|
||||
|
||||
if s.having != nil {
|
||||
err := out.writeHaving(select_statement, s.having)
|
||||
err := out.writeHaving(selectStatement, s.having)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -226,7 +229,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
}
|
||||
|
||||
if s.orderBy != nil {
|
||||
err := out.writeOrderBy(select_statement, s.orderBy)
|
||||
err := out.writeOrderBy(selectStatement, s.orderBy)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -236,19 +239,19 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
if s.limit >= 0 {
|
||||
out.newLine()
|
||||
out.writeString("LIMIT")
|
||||
out.insertPreparedArgument(s.limit)
|
||||
out.insertParametrizedArgument(s.limit)
|
||||
}
|
||||
|
||||
if s.offset >= 0 {
|
||||
out.newLine()
|
||||
out.writeString("OFFSET")
|
||||
out.insertPreparedArgument(s.offset)
|
||||
out.insertParametrizedArgument(s.offset)
|
||||
}
|
||||
|
||||
if s.lockFor != nil {
|
||||
out.newLine()
|
||||
out.writeString("FOR")
|
||||
err := s.lockFor.serialize(select_statement, out)
|
||||
err := s.lockFor.serialize(selectStatement, out)
|
||||
|
||||
if err != nil {
|
||||
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 {
|
||||
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) {
|
||||
|
|
@ -292,8 +295,7 @@ func (s *selectStatementImpl) ExecContext(db execution.DB, context context.Conte
|
|||
return execContext(s.parent, db, context)
|
||||
}
|
||||
|
||||
// SelectLock
|
||||
|
||||
// SelectLock is interface for SELECT statement locks
|
||||
type SelectLock interface {
|
||||
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"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return newSetStatementImpl(intersect, true, toSelectList(lhs, rhs, selects...))
|
||||
}
|
||||
|
||||
func EXCEPT(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||
return newSetStatementImpl(except, false, toSelectList(lhs, rhs, selects...))
|
||||
// EXCEPT returns all rows that are in the result of query lhs but not in the result of query rhs.
|
||||
// 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 {
|
||||
return newSetStatementImpl(except, true, toSelectList(lhs, rhs, selects...))
|
||||
// EXCEPT_ALL returns all rows that are in the result of query lhs but not in the result of query rhs.
|
||||
// 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 {
|
||||
|
|
@ -102,7 +114,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
}
|
||||
|
||||
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()
|
||||
|
|
@ -124,7 +136,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
return errors.New("jet: select statement is nil")
|
||||
}
|
||||
|
||||
err := selectStmt.serialize(set_statement, out)
|
||||
err := selectStmt.serialize(setStatement, out)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -136,7 +148,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
out.writeString(")")
|
||||
|
||||
if s.orderBy != nil {
|
||||
err := out.writeOrderBy(set_statement, s.orderBy)
|
||||
err := out.writeOrderBy(setStatement, s.orderBy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -145,13 +157,13 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
|||
if s.limit >= 0 {
|
||||
out.newLine()
|
||||
out.writeString("LIMIT")
|
||||
out.insertPreparedArgument(s.limit)
|
||||
out.insertParametrizedArgument(s.limit)
|
||||
}
|
||||
|
||||
if s.offset >= 0 {
|
||||
out.newLine()
|
||||
out.writeString("OFFSET")
|
||||
out.insertPreparedArgument(s.offset)
|
||||
out.insertParametrizedArgument(s.offset)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func TestUnionTwoSelect(t *testing.T) {
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
(
|
||||
(
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
|
|
@ -27,8 +27,8 @@ func TestUnionTwoSelect(t *testing.T) {
|
|||
|
||||
unionStmt2 := UNION(table1.SELECT(table1Col1), table2.SELECT(table2Col3))
|
||||
|
||||
assertStatement(t, unionStmt1, expectedSql)
|
||||
assertStatement(t, unionStmt2, expectedSql)
|
||||
assertStatement(t, unionStmt1, expectedSQL)
|
||||
assertStatement(t, unionStmt2, expectedSQL)
|
||||
}
|
||||
|
||||
func TestUnionNilSelect(t *testing.T) {
|
||||
|
|
@ -49,7 +49,7 @@ func TestUnionThreeSelect1(t *testing.T) {
|
|||
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) {
|
||||
|
|
@ -82,7 +82,7 @@ func TestUnionThreeSelect2(t *testing.T) {
|
|||
table3.SELECT(table3Col1),
|
||||
)
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
(
|
||||
(
|
||||
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) {
|
||||
|
|
@ -155,7 +155,7 @@ OFFSET $2;
|
|||
}
|
||||
|
||||
func TestUnionInUnion(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
(
|
||||
(
|
||||
SELECT table2.col3 AS "table2.col3",
|
||||
|
|
@ -182,7 +182,7 @@ func TestUnionInUnion(t *testing.T) {
|
|||
UNION_ALL(table1.SELECT(table1Col1), table2.SELECT(table2Col3)),
|
||||
)
|
||||
|
||||
assertStatement(t, query, expectedSql)
|
||||
assertStatement(t, query, expectedSQL)
|
||||
}
|
||||
|
||||
func TestUnionALL(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
//Statement is common interface for all statements(SELECT, INSERT, UPDATE, DELETE, LOCK)
|
||||
type Statement interface {
|
||||
// Sql returns parametrized sql query with list of arguments.
|
||||
// err is returned if statement is not composed correctly
|
||||
|
|
@ -37,14 +38,14 @@ func debugSql(statement Statement) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
debugSqlQuery := sqlQuery
|
||||
debugSQLQuery := sqlQuery
|
||||
|
||||
for i, arg := range args {
|
||||
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 {
|
||||
|
|
@ -57,7 +58,7 @@ func query(statement Statement, db execution.DB, destination interface{}) error
|
|||
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()
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// StringExpression interface
|
||||
type StringExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -108,6 +109,9 @@ func newStringExpressionWrap(expression Expression) StringExpression {
|
|||
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 {
|
||||
return newStringExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
14
table.go
14
table.go
|
|
@ -36,18 +36,21 @@ type writableTable interface {
|
|||
LOCK() LockStatement
|
||||
}
|
||||
|
||||
// ReadableTable interface
|
||||
type ReadableTable interface {
|
||||
table
|
||||
readableTable
|
||||
clause
|
||||
}
|
||||
|
||||
// WritableTable interface
|
||||
type WritableTable interface {
|
||||
table
|
||||
writableTable
|
||||
clause
|
||||
}
|
||||
|
||||
// Table interface
|
||||
type Table interface {
|
||||
table
|
||||
readableTable
|
||||
|
|
@ -110,6 +113,7 @@ func (w *writableTableInterfaceImpl) LOCK() LockStatement {
|
|||
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 {
|
||||
|
||||
t := &tableImpl{
|
||||
|
|
@ -196,20 +200,20 @@ type joinTable struct {
|
|||
|
||||
lhs ReadableTable
|
||||
rhs ReadableTable
|
||||
join_type joinType
|
||||
joinType joinType
|
||||
onCondition BoolExpression
|
||||
}
|
||||
|
||||
func newJoinTable(
|
||||
lhs ReadableTable,
|
||||
rhs ReadableTable,
|
||||
join_type joinType,
|
||||
joinType joinType,
|
||||
onCondition BoolExpression) ReadableTable {
|
||||
|
||||
joinTable := &joinTable{
|
||||
lhs: lhs,
|
||||
rhs: rhs,
|
||||
join_type: join_type,
|
||||
joinType: joinType,
|
||||
onCondition: onCondition,
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +249,7 @@ func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options
|
|||
|
||||
out.newLine()
|
||||
|
||||
switch t.join_type {
|
||||
switch t.joinType {
|
||||
case innerJoin:
|
||||
out.writeString("INNER JOIN")
|
||||
case leftJoin:
|
||||
|
|
@ -266,7 +270,7 @@ func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options
|
|||
return
|
||||
}
|
||||
|
||||
if t.onCondition == nil && t.join_type != crossJoin {
|
||||
if t.onCondition == nil && t.joinType != crossJoin {
|
||||
return errors.New("jet: join condition is nil")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ func TestFloatOperators(t *testing.T) {
|
|||
CEIL(AllTypes.Real),
|
||||
FLOOR(AllTypes.Real),
|
||||
ROUND(AllTypes.Decimal),
|
||||
ROUND(AllTypes.Decimal, Int(3)).AS("round"),
|
||||
ROUND(AllTypes.Decimal, AllTypes.Integer).AS("round"),
|
||||
SIGN(AllTypes.Real),
|
||||
TRUNC(AllTypes.Decimal),
|
||||
TRUNC(AllTypes.Decimal, Int(1)),
|
||||
|
|
@ -361,7 +361,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
|||
args []interface{}
|
||||
}
|
||||
|
||||
subQueries := map[ExpressionTable]expected{}
|
||||
subQueries := map[SelectTable]expected{}
|
||||
|
||||
selectSubQuery := AllTypes.SELECT(
|
||||
AllTypes.Boolean,
|
||||
|
|
@ -378,7 +378,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
|||
LIMIT(2).
|
||||
AsTable("subQuery")
|
||||
|
||||
var selectExpectedSql = ` (
|
||||
var selectexpectedSQL = ` (
|
||||
SELECT all_types.boolean AS "all_types.boolean",
|
||||
all_types.integer AS "all_types.integer",
|
||||
all_types.real AS "all_types.real",
|
||||
|
|
@ -424,7 +424,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
|||
).
|
||||
AsTable("subQuery")
|
||||
|
||||
unionExpectedSql := `
|
||||
unionexpectedSQL := `
|
||||
(
|
||||
(
|
||||
SELECT all_types.boolean AS "all_types.boolean",
|
||||
|
|
@ -458,8 +458,8 @@ func TestSubQueryColumnReference(t *testing.T) {
|
|||
)
|
||||
) AS "subQuery"`
|
||||
|
||||
subQueries[selectSubQuery] = expected{sql: selectExpectedSql, args: []interface{}{int64(2)}}
|
||||
subQueries[unionSubQuery] = expected{sql: unionExpectedSql, args: []interface{}{int64(1), int64(1), int64(1)}}
|
||||
subQueries[selectSubQuery] = expected{sql: selectexpectedSQL, args: []interface{}{int64(2)}}
|
||||
subQueries[unionSubQuery] = expected{sql: unionexpectedSQL, args: []interface{}{int64(1), int64(1), int64(1)}}
|
||||
|
||||
for subQuery, expected := range subQueries {
|
||||
boolColumn := AllTypes.Boolean.From(subQuery)
|
||||
|
|
@ -487,7 +487,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
|||
).
|
||||
FROM(subQuery)
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
SELECT "subQuery"."all_types.boolean" AS "all_types.boolean",
|
||||
"subQuery"."all_types.integer" AS "all_types.integer",
|
||||
"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"
|
||||
FROM`
|
||||
|
||||
assertStatementSql(t, stmt1, expectedSql+expected.sql+";\n", expected.args...)
|
||||
assertStatementSql(t, stmt1, expectedSQL+expected.sql+";\n", expected.args...)
|
||||
|
||||
dest1 := []model.AllTypes{}
|
||||
err := stmt1.Query(db, &dest1)
|
||||
|
|
@ -523,7 +523,7 @@ FROM`
|
|||
|
||||
//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{}
|
||||
err = stmt2.Query(db, &dest2)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
func TestDeleteWithWhere(t *testing.T) {
|
||||
initForDeleteTest(t)
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
DELETE FROM test_sample.link
|
||||
WHERE link.name IN ('Gmail', 'Outlook');
|
||||
`
|
||||
|
|
@ -19,14 +19,14 @@ WHERE link.name IN ('Gmail', 'Outlook');
|
|||
DELETE().
|
||||
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
||||
|
||||
assertStatementSql(t, deleteStmt, expectedSql, "Gmail", "Outlook")
|
||||
assertStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
|
||||
assertExec(t, deleteStmt, 2)
|
||||
}
|
||||
|
||||
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
||||
initForDeleteTest(t)
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
DELETE FROM test_sample.link
|
||||
WHERE link.name IN ('Gmail', 'Outlook')
|
||||
RETURNING link.id AS "link.id",
|
||||
|
|
@ -39,7 +39,7 @@ RETURNING link.id AS "link.id",
|
|||
WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))).
|
||||
RETURNING(Link.AllColumns)
|
||||
|
||||
assertStatementSql(t, deleteStmt, expectedSql, "Gmail", "Outlook")
|
||||
assertStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
|
||||
|
||||
dest := []model.Link{}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
func TestInsertValues(t *testing.T) {
|
||||
cleanUpLinkTable(t)
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
INSERT INTO test_sample.link (id, url, name, description) VALUES
|
||||
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', 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).
|
||||
RETURNING(Link.AllColumns)
|
||||
|
||||
assertStatementSql(t, insertQuery, expectedSql,
|
||||
assertStatementSql(t, insertQuery, expectedSQL,
|
||||
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||
101, "http://www.google.com", "Google",
|
||||
102, "http://www.yahoo.com", "Yahoo", nil)
|
||||
|
|
@ -74,7 +74,7 @@ RETURNING link.id AS "link.id",
|
|||
func TestInsertEmptyColumnList(t *testing.T) {
|
||||
cleanUpLinkTable(t)
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
INSERT INTO test_sample.link VALUES
|
||||
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT);
|
||||
`
|
||||
|
|
@ -82,7 +82,7 @@ INSERT INTO test_sample.link VALUES
|
|||
stmt := Link.INSERT().
|
||||
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT)
|
||||
|
||||
assertStatementSql(t, stmt, expectedSql,
|
||||
assertStatementSql(t, stmt, expectedSQL,
|
||||
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial")
|
||||
|
||||
assertExec(t, stmt, 1)
|
||||
|
|
@ -90,7 +90,7 @@ INSERT INTO test_sample.link VALUES
|
|||
|
||||
func TestInsertModelObject(t *testing.T) {
|
||||
cleanUpLinkTable(t)
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
INSERT INTO test_sample.link (url, name) VALUES
|
||||
('http://www.duckduckgo.com', 'Duck Duck go');
|
||||
`
|
||||
|
|
@ -104,7 +104,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
|||
INSERT(Link.URL, Link.Name).
|
||||
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)
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
|||
}
|
||||
|
||||
func TestInsertModelsObject(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
INSERT INTO test_sample.link (url, name) VALUES
|
||||
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial'),
|
||||
('http://www.google.com', 'Google'),
|
||||
|
|
@ -142,7 +142,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
|||
INSERT(Link.URL, Link.Name).
|
||||
MODELS([]model.Link{tutorial, google, yahoo})
|
||||
|
||||
assertStatementSql(t, stmt, expectedSql,
|
||||
assertStatementSql(t, stmt, expectedSQL,
|
||||
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||
"http://www.google.com", "Google",
|
||||
"http://www.yahoo.com", "Yahoo")
|
||||
|
|
@ -151,7 +151,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
|||
}
|
||||
|
||||
func TestInsertUsingMutableColumns(t *testing.T) {
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
INSERT INTO test_sample.link (url, name, description) VALUES
|
||||
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
|
||||
('http://www.google.com', 'Google', NULL),
|
||||
|
|
@ -175,7 +175,7 @@ INSERT INTO test_sample.link (url, name, description) VALUES
|
|||
MODEL(google).
|
||||
MODELS([]model.Link{google, yahoo})
|
||||
|
||||
assertStatementSql(t, stmt, expectedSql,
|
||||
assertStatementSql(t, stmt, expectedSQL,
|
||||
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||
"http://www.google.com", "Google", nil,
|
||||
"http://www.google.com", "Google", nil,
|
||||
|
|
@ -190,7 +190,7 @@ func TestInsertQuery(t *testing.T) {
|
|||
Exec(db)
|
||||
assert.NilError(t, err)
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
INSERT INTO test_sample.link (url, name) (
|
||||
SELECT link.url AS "link.url",
|
||||
link.name AS "link.name"
|
||||
|
|
@ -212,7 +212,7 @@ RETURNING link.id AS "link.id",
|
|||
).
|
||||
RETURNING(Link.AllColumns)
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(0))
|
||||
assertStatementSql(t, query, expectedSQL, int64(0))
|
||||
|
||||
dest := []model.Link{}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ FROM test_sample.person;
|
|||
|
||||
func TestSelecSelfJoin1(t *testing.T) {
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
SELECT employee.employee_id AS "employee.employee_id",
|
||||
employee.first_name AS "employee.first_name",
|
||||
employee.last_name AS "employee.last_name",
|
||||
|
|
@ -97,7 +97,7 @@ ORDER BY employee.employee_id;
|
|||
).
|
||||
ORDER_BY(Employee.EmployeeID)
|
||||
|
||||
assertStatementSql(t, query, expectedSql)
|
||||
assertStatementSql(t, query, expectedSQL)
|
||||
|
||||
type Manager model.Employee
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSelect_ScanToStruct(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
|
|
@ -24,7 +24,7 @@ WHERE actor.actor_id = 1;
|
|||
DISTINCT().
|
||||
WHERE(Actor.ActorID.EQ(Int(1)))
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(1))
|
||||
assertStatementSql(t, query, expectedSQL, int64(1))
|
||||
|
||||
actor := model.Actor{}
|
||||
err := query.Query(db, &actor)
|
||||
|
|
@ -42,7 +42,7 @@ WHERE actor.actor_id = 1;
|
|||
}
|
||||
|
||||
func TestClassicSelect(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT payment.payment_id AS "payment.payment_id",
|
||||
payment.customer_id AS "payment.customer_id",
|
||||
payment.staff_id AS "payment.staff_id",
|
||||
|
|
@ -74,7 +74,7 @@ LIMIT 30;
|
|||
ORDER_BY(Payment.PaymentID.ASC()).
|
||||
LIMIT(30)
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(30))
|
||||
assertStatementSql(t, query, expectedSQL, int64(30))
|
||||
|
||||
dest := []model.Payment{}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ LIMIT 30;
|
|||
}
|
||||
|
||||
func TestSelect_ScanToSlice(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.store_id AS "customer.store_id",
|
||||
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())
|
||||
|
||||
assertStatementSql(t, query, expectedSql)
|
||||
assertStatementSql(t, query, expectedSQL)
|
||||
|
||||
err := query.Query(db, &customers)
|
||||
assert.NilError(t, err)
|
||||
|
|
@ -116,7 +116,7 @@ ORDER BY customer.customer_id ASC;
|
|||
}
|
||||
|
||||
func TestSelectAndUnionInProjection(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT payment.payment_id AS "payment.payment_id",
|
||||
(
|
||||
SELECT customer.customer_id AS "customer.customer_id"
|
||||
|
|
@ -156,12 +156,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) {
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT film_actor.actor_id AS "film_actor.actor_id",
|
||||
film_actor.film_id AS "film_actor.film_id",
|
||||
film_actor.last_update AS "film_actor.last_update",
|
||||
|
|
@ -224,7 +224,7 @@ LIMIT 1000;
|
|||
ORDER_BY(Film.FilmID.ASC()).
|
||||
LIMIT(1000)
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(1000))
|
||||
assertStatementSql(t, query, expectedSQL, int64(1000))
|
||||
|
||||
var languageActorFilm []struct {
|
||||
model.Language
|
||||
|
|
@ -253,7 +253,7 @@ LIMIT 1000;
|
|||
}
|
||||
|
||||
func TestJoinQuerySlice(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT language.language_id AS "language.language_id",
|
||||
language.name AS "language.name",
|
||||
language.last_update AS "language.last_update",
|
||||
|
|
@ -290,7 +290,7 @@ LIMIT 15;
|
|||
WHERE(Film.Rating.EQ(enum.MpaaRating.Nc17)).
|
||||
LIMIT(15)
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(15))
|
||||
assertStatementSql(t, query, expectedSQL, int64(15))
|
||||
|
||||
err := query.Query(db, &filmsPerLanguage)
|
||||
|
||||
|
|
@ -657,7 +657,7 @@ func TestSelectOrderByAscDesc(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSelectFullJoin(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.store_id AS "customer.store_id",
|
||||
customer.first_name AS "customer.first_name",
|
||||
|
|
@ -685,7 +685,7 @@ ORDER BY customer.customer_id ASC;
|
|||
SELECT(Customer.AllColumns, Address.AllColumns).
|
||||
ORDER_BY(Customer.CustomerID.ASC())
|
||||
|
||||
assertStatementSql(t, query, expectedSql)
|
||||
assertStatementSql(t, query, expectedSQL)
|
||||
|
||||
allCustomersAndAddress := []struct {
|
||||
Address *model.Address
|
||||
|
|
@ -708,7 +708,7 @@ ORDER BY customer.customer_id ASC;
|
|||
}
|
||||
|
||||
func TestSelectFullCrossJoin(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.store_id AS "customer.store_id",
|
||||
customer.first_name AS "customer.first_name",
|
||||
|
|
@ -738,7 +738,7 @@ LIMIT 1000;
|
|||
ORDER_BY(Customer.CustomerID.ASC()).
|
||||
LIMIT(1000)
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(1000))
|
||||
assertStatementSql(t, query, expectedSQL, int64(1000))
|
||||
|
||||
var customerAddresCrosJoined []struct {
|
||||
model.Customer
|
||||
|
|
@ -753,7 +753,7 @@ LIMIT 1000;
|
|||
}
|
||||
|
||||
func TestSelectSelfJoin(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT f1.film_id AS "f1.film_id",
|
||||
f1.title AS "f1.title",
|
||||
f1.description AS "f1.description",
|
||||
|
|
@ -793,7 +793,7 @@ ORDER BY f1.film_id ASC;
|
|||
SELECT(f1.AllColumns, f2.AllColumns).
|
||||
ORDER_BY(f1.FilmID.ASC())
|
||||
|
||||
assertStatementSql(t, query, expectedSql)
|
||||
assertStatementSql(t, query, expectedSQL)
|
||||
|
||||
type F1 model.Film
|
||||
type F2 model.Film
|
||||
|
|
@ -813,7 +813,7 @@ ORDER BY f1.film_id ASC;
|
|||
}
|
||||
|
||||
func TestSelectAliasColumn(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT f1.title AS "thesame_length_films.title1",
|
||||
f2.title AS "thesame_length_films.title2",
|
||||
f1.length AS "thesame_length_films.length"
|
||||
|
|
@ -835,7 +835,7 @@ LIMIT 1000;
|
|||
ORDER_BY(f1.Length.ASC(), f1.Title.ASC(), f2.Title.ASC()).
|
||||
LIMIT(1000)
|
||||
|
||||
assertStatementSql(t, query, expectedSql, int64(1000))
|
||||
assertStatementSql(t, query, expectedSQL, int64(1000))
|
||||
|
||||
type thesameLengthFilms struct {
|
||||
Title1 string
|
||||
|
|
@ -928,7 +928,7 @@ FROM dvds.film;
|
|||
}
|
||||
|
||||
func TestSelectQueryScalar(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT film.film_id AS "film.film_id",
|
||||
film.title AS "film.title",
|
||||
film.description AS "film.description",
|
||||
|
|
@ -960,7 +960,7 @@ ORDER BY film.film_id ASC;
|
|||
WHERE(Film.RentalRate.EQ(maxFilmRentalRate)).
|
||||
ORDER_BY(Film.FilmID.ASC())
|
||||
|
||||
assertStatementSql(t, query, expectedSql)
|
||||
assertStatementSql(t, query, expectedSQL)
|
||||
|
||||
maxRentalRateFilms := []model.Film{}
|
||||
err := query.Query(db, &maxRentalRateFilms)
|
||||
|
|
@ -989,7 +989,7 @@ ORDER BY film.film_id ASC;
|
|||
}
|
||||
|
||||
func TestSelectGroupByHaving(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT payment.customer_id AS "customer_payment_sum.customer_id",
|
||||
SUM(payment.amount) AS "customer_payment_sum.amount_sum",
|
||||
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)),
|
||||
)
|
||||
|
||||
assertStatementSql(t, customersPaymentQuery, expectedSql, float64(100))
|
||||
assertStatementSql(t, customersPaymentQuery, expectedSQL, float64(100))
|
||||
|
||||
type CustomerPaymentSum struct {
|
||||
CustomerID int16
|
||||
|
|
@ -1047,7 +1047,7 @@ ORDER BY SUM(payment.amount) ASC;
|
|||
}
|
||||
|
||||
func TestSelectGroupBy2(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.store_id AS "customer.store_id",
|
||||
customer.first_name AS "customer.first_name",
|
||||
|
|
@ -1088,7 +1088,7 @@ ORDER BY customer_payment_sum."amount_sum" ASC;
|
|||
).
|
||||
ORDER_BY(amountSum.ASC())
|
||||
|
||||
assertStatementSql(t, query, expectedSql)
|
||||
assertStatementSql(t, query, expectedSQL)
|
||||
|
||||
type CustomerWithAmounts struct {
|
||||
Customer *model.Customer
|
||||
|
|
@ -1157,7 +1157,7 @@ func TestSelectStaff(t *testing.T) {
|
|||
|
||||
func TestSelectTimeColumns(t *testing.T) {
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT payment.payment_id AS "payment.payment_id",
|
||||
payment.customer_id AS "payment.customer_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))).
|
||||
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{}
|
||||
|
||||
|
|
@ -1260,8 +1260,8 @@ func TestAllSetOperators(t *testing.T) {
|
|||
UNION_ALL,
|
||||
INTERSECT,
|
||||
INTERSECT_ALL,
|
||||
EXCEPT,
|
||||
EXCEPT_ALL,
|
||||
//EXCEPT,
|
||||
//EXCEPT_ALL,
|
||||
}
|
||||
|
||||
expectedDestLen := []int{
|
||||
|
|
@ -1316,7 +1316,7 @@ LIMIT 20;
|
|||
}
|
||||
|
||||
func TestLockTable(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
LOCK TABLE dvds.address IN`
|
||||
|
||||
var testData = []TableLockMode{
|
||||
|
|
@ -1333,7 +1333,7 @@ LOCK TABLE dvds.address IN`
|
|||
for _, lockMode := range testData {
|
||||
query := Address.LOCK().IN(lockMode)
|
||||
|
||||
assertStatementSql(t, query, expectedSql+" "+string(lockMode)+" MODE;\n")
|
||||
assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE;\n")
|
||||
|
||||
tx, _ := db.Begin()
|
||||
|
||||
|
|
@ -1349,7 +1349,7 @@ LOCK TABLE dvds.address IN`
|
|||
for _, lockMode := range testData {
|
||||
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()
|
||||
|
||||
|
|
@ -1373,7 +1373,7 @@ func getRowLockTestData() map[SelectLock]string {
|
|||
}
|
||||
|
||||
func TestRowLock(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
SELECT *
|
||||
FROM dvds.address
|
||||
LIMIT 3
|
||||
|
|
@ -1385,7 +1385,7 @@ FOR`
|
|||
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||
query.FOR(lockType)
|
||||
|
||||
assertStatementSql(t, query, expectedSql+" "+lockTypeStr+";\n", int64(3))
|
||||
assertStatementSql(t, query, expectedSQL+" "+lockTypeStr+";\n", int64(3))
|
||||
|
||||
tx, _ := db.Begin()
|
||||
|
||||
|
|
@ -1401,7 +1401,7 @@ FOR`
|
|||
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||
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()
|
||||
|
||||
|
|
@ -1417,7 +1417,7 @@ FOR`
|
|||
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||
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()
|
||||
|
||||
|
|
@ -1433,7 +1433,7 @@ FOR`
|
|||
|
||||
func TestQuickStart(t *testing.T) {
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
SELECT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_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(),
|
||||
)
|
||||
|
||||
assertStatementSql(t, stmt, expectedSql, "English", "Action", int64(180))
|
||||
assertStatementSql(t, stmt, expectedSQL, "English", "Action", int64(180))
|
||||
|
||||
var dest []struct {
|
||||
model.Actor
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ func TestUpdateValues(t *testing.T) {
|
|||
SET("Bong", "http://bong.com").
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
UPDATE test_sample.link
|
||||
SET (name, url) = ('Bong', 'http://bong.com')
|
||||
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)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ func TestUpdateWithSubQueries(t *testing.T) {
|
|||
).
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE test_sample.link
|
||||
SET (name, url) = ((
|
||||
SELECT 'Bong'
|
||||
|
|
@ -66,7 +66,7 @@ SET (name, url) = ((
|
|||
WHERE link.name = 'Bing';
|
||||
`
|
||||
|
||||
assertStatementSql(t, query, expectedSql, "Bong", "Bing", "Bing")
|
||||
assertStatementSql(t, query, expectedSQL, "Bong", "Bing", "Bing")
|
||||
|
||||
assertExec(t, query, 1)
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ WHERE link.name = 'Bing';
|
|||
func TestUpdateAndReturning(t *testing.T) {
|
||||
setupLinkTableForUpdateTest(t)
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE test_sample.link
|
||||
SET (name, url) = ('DuckDuckGo', 'http://www.duckduckgo.com')
|
||||
WHERE link.name = 'Ask'
|
||||
|
|
@ -90,7 +90,7 @@ RETURNING link.id AS "link.id",
|
|||
WHERE(Link.Name.EQ(String("Ask"))).
|
||||
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{}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ func TestUpdateWithSelect(t *testing.T) {
|
|||
).
|
||||
WHERE(Link.ID.EQ(Int(0)))
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE test_sample.link
|
||||
SET (id, url, name, description) = (
|
||||
SELECT link.id AS "link.id",
|
||||
|
|
@ -124,7 +124,7 @@ SET (id, url, name, description) = (
|
|||
)
|
||||
WHERE link.id = 0;
|
||||
`
|
||||
assertStatementSql(t, stmt, expectedSql, int64(0), int64(0))
|
||||
assertStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
|
||||
|
||||
assertExec(t, stmt, 1)
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ func TestUpdateWithInvalidSelect(t *testing.T) {
|
|||
).
|
||||
WHERE(Link.ID.EQ(Int(0)))
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
UPDATE test_sample.link
|
||||
SET (id, url, name, description) = (
|
||||
SELECT link.id AS "link.id",
|
||||
|
|
@ -149,7 +149,7 @@ SET (id, url, name, description) = (
|
|||
)
|
||||
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")
|
||||
}
|
||||
|
|
@ -168,12 +168,12 @@ func TestUpdateWithModelData(t *testing.T) {
|
|||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
||||
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE test_sample.link
|
||||
SET (id, url, name, description) = (201, 'http://www.duckduckgo.com', 'DuckDuckGo', NULL)
|
||||
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)
|
||||
}
|
||||
|
|
@ -195,12 +195,12 @@ func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
|
|||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
UPDATE test_sample.link
|
||||
SET (description, name, url) = (NULL, 'DuckDuckGo', 'http://www.duckduckgo.com')
|
||||
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)
|
||||
}
|
||||
|
|
@ -231,12 +231,12 @@ func TestUpdateWithInvalidModelData(t *testing.T) {
|
|||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int(int64(link.Ident))))
|
||||
|
||||
var expectedSql = `
|
||||
var expectedSQL = `
|
||||
UPDATE test_sample.link
|
||||
SET (id, url, name, description, rel) = ('http://www.duckduckgo.com', 'DuckDuckGo', NULL, NULL)
|
||||
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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// TimeExpression interface
|
||||
type TimeExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -68,10 +69,6 @@ func newPrefixTimeExpression(operator string, expression Expression) TimeExpress
|
|||
return &timeExpr
|
||||
}
|
||||
|
||||
func INTERVAL(interval string) Expression {
|
||||
return newPrefixTimeExpression("INTERVAL", literal(interval))
|
||||
}
|
||||
|
||||
//---------------------------------------------------//
|
||||
|
||||
type timeExpressionWrapper struct {
|
||||
|
|
@ -85,6 +82,9 @@ func newTimeExpressionWrap(expression Expression) TimeExpression {
|
|||
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 {
|
||||
return newTimeExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// TimestampExpression interface
|
||||
type TimestampExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -63,6 +64,9 @@ func newTimestampExpressionWrap(expression Expression) TimestampExpression {
|
|||
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 {
|
||||
return newTimestampExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package jet
|
||||
|
||||
// TimestampzExpression interface
|
||||
type TimestampzExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -63,6 +64,9 @@ func newTimestampzExpressionWrap(expression Expression) TimestampzExpression {
|
|||
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 {
|
||||
return newTimestampzExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,25 @@
|
|||
package jet
|
||||
|
||||
// TimezExpression interface 'time with time zone'
|
||||
type TimezExpression interface {
|
||||
Expression
|
||||
|
||||
//EQ
|
||||
EQ(rhs TimezExpression) BoolExpression
|
||||
//NOT_EQ
|
||||
NOT_EQ(rhs TimezExpression) BoolExpression
|
||||
//IS_DISTINCT_FROM
|
||||
IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression
|
||||
//IS_NOT_DISTINCT_FROM
|
||||
IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression
|
||||
|
||||
//LT
|
||||
LT(rhs TimezExpression) BoolExpression
|
||||
//LT_EQ
|
||||
LT_EQ(rhs TimezExpression) BoolExpression
|
||||
//GT
|
||||
GT(rhs TimezExpression) BoolExpression
|
||||
//GT_EQ
|
||||
GT_EQ(rhs TimezExpression) BoolExpression
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +90,9 @@ func newTimezExpressionWrap(expression Expression) TimezExpression {
|
|||
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 {
|
||||
return newTimezExpressionWrap(expression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/go-jet/jet/execution"
|
||||
)
|
||||
|
||||
// UpdateStatement is interface of SQL UPDATE statement
|
||||
type UpdateStatement interface {
|
||||
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")
|
||||
}
|
||||
|
||||
if err = u.table.serialize(update_statement, out); err != nil {
|
||||
if err = u.table.serialize(updateStatement, out); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +101,7 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
|||
out.writeString("(")
|
||||
}
|
||||
|
||||
err = serializeClauseList(update_statement, u.row, out)
|
||||
err = serializeClauseList(updateStatement, u.row, out)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -114,11 +115,11 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
|||
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
|
||||
}
|
||||
|
||||
if err = out.writeReturning(update_statement, u.returning); err != nil {
|
||||
if err = out.writeReturning(updateStatement, u.returning); err != nil {
|
||||
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 {
|
||||
return queryContext(u, db, context, destination)
|
||||
return queryContext(context, u, db, destination)
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
func TestUpdateWithOneValue(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET col_int = $1
|
||||
WHERE table1.col_int >= $2;
|
||||
|
|
@ -14,11 +14,11 @@ WHERE table1.col_int >= $2;
|
|||
SET(1).
|
||||
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) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET (col_int, col_float) = ($1, $2)
|
||||
WHERE table1.col_int >= $3;
|
||||
|
|
@ -27,11 +27,11 @@ WHERE table1.col_int >= $3;
|
|||
SET(1, 22.2).
|
||||
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) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET 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))).
|
||||
RETURNING(table1Col1)
|
||||
|
||||
assertStatement(t, stmt, expectedSql, int64(2))
|
||||
assertStatement(t, stmt, expectedSQL, int64(2))
|
||||
}
|
||||
|
||||
func TestUpdateColumnsWithSelect(t *testing.T) {
|
||||
expectedSql := `
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET (col1, 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))).
|
||||
RETURNING(table1Col1)
|
||||
|
||||
assertStatement(t, stmt, expectedSql, int64(2))
|
||||
assertStatement(t, stmt, expectedSQL, int64(2))
|
||||
}
|
||||
|
||||
func TestInvalidInputs(t *testing.T) {
|
||||
|
|
|
|||
10
utils.go
10
utils.go
|
|
@ -7,7 +7,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func serializeOrderByClauseList(statement statementType, orderByClauses []OrderByClause, out *sqlBuilder) error {
|
||||
func serializeOrderByClauseList(statement statementType, orderByClauses []orderByClause, out *sqlBuilder) error {
|
||||
|
||||
for i, value := range orderByClauses {
|
||||
if i > 0 {
|
||||
|
|
@ -32,7 +32,7 @@ func serializeGroupByClauseList(statement statementType, clauses []groupByClause
|
|||
}
|
||||
|
||||
if c == nil {
|
||||
return errors.New("jet: nil clause.")
|
||||
return errors.New("jet: nil clause")
|
||||
}
|
||||
|
||||
if err = c.serializeForGroupBy(statement, out); err != nil {
|
||||
|
|
@ -51,7 +51,7 @@ func serializeClauseList(statement statementType, clauses []clause, out *sqlBuil
|
|||
}
|
||||
|
||||
if c == nil {
|
||||
return errors.New("jet: nil clause.")
|
||||
return errors.New("jet: nil clause")
|
||||
}
|
||||
|
||||
if err = c.serialize(statement, out); err != nil {
|
||||
|
|
@ -131,9 +131,9 @@ func isNil(v interface{}) bool {
|
|||
func valueToClause(value interface{}) clause {
|
||||
if clause, ok := value.(clause); ok {
|
||||
return clause
|
||||
} else {
|
||||
return literal(value)
|
||||
}
|
||||
|
||||
return literal(value)
|
||||
}
|
||||
|
||||
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{}) {
|
||||
out := sqlBuilder{}
|
||||
err := clause.serialize(select_statement, &out)
|
||||
err := clause.serialize(selectStatement, &out)
|
||||
|
||||
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) {
|
||||
out := sqlBuilder{}
|
||||
err := clause.serialize(select_statement, &out)
|
||||
err := clause.serialize(selectStatement, &out)
|
||||
|
||||
//fmt.Println(out.buff.String())
|
||||
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{}) {
|
||||
out := sqlBuilder{}
|
||||
err := projection.serializeForProjection(select_statement, &out)
|
||||
err := projection.serializeForProjection(selectStatement, &out)
|
||||
|
||||
assert.NilError(t, err)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue