Additional documentation.

This commit is contained in:
go-jet 2019-07-18 17:43:11 +02:00
parent d253a35161
commit b10270b502
48 changed files with 892 additions and 699 deletions

View file

@ -1,10 +1,11 @@
# Jet
[![Documentation](https://godoc.org/github.com/go-jet/jet?status.svg)](http://godoc.org/github.com/go-jet/jet)
[![CircleCI](https://circleci.com/gh/go-jet/jet/tree/develop.svg?style=svg&circle-token=97f255c6a4a3ab6590ea2e9195eb3ebf9f97b4a7)](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

View file

@ -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

View file

@ -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)
}

View file

@ -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,

View file

@ -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:

View file

@ -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 "" }

View file

@ -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 := &timestampColumnImpl{}
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 := &timestampzColumnImpl{}
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

View file

@ -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)
}

View file

@ -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
View file

@ -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

View file

@ -6,6 +6,7 @@ type enumValue struct {
name string
}
// NewEnumValue creates new named enum value
func NewEnumValue(name string) StringExpression {
enumValue := &enumValue{name: name}

View file

@ -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

View file

@ -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
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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`)
}

View file

@ -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) {

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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()
)

View file

@ -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 := &timestampLiteral{}
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 := &timestampzLiteral{}
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

View file

@ -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) {

View file

@ -1,5 +1,6 @@
package jet
// NumericExpression is common interface for all integer and float expressions
type NumericExpression interface {
Expression
numericExpression

View file

@ -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

View file

@ -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))

View file

@ -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}
}

View file

@ -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 {

View file

@ -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
View 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
}

View file

@ -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

View file

@ -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) {

View file

@ -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 {

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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)

View file

@ -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{}

View file

@ -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{}

View file

@ -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

View file

@ -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

View file

@ -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")
}

View file

@ -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)
}

View file

@ -1,5 +1,6 @@
package jet
// TimestampExpression interface
type TimestampExpression interface {
Expression
@ -63,6 +64,9 @@ func newTimestampExpressionWrap(expression Expression) TimestampExpression {
return &timestampExpressionWrap
}
// 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)
}

View file

@ -1,5 +1,6 @@
package jet
// TimestampzExpression interface
type TimestampzExpression interface {
Expression
@ -63,6 +64,9 @@ func newTimestampzExpressionWrap(expression Expression) TimestampzExpression {
return &timestampzExpressionWrap
}
// 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)
}

View file

@ -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)
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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 {

View file

@ -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)