init - add project files
This commit is contained in:
132
tools/jet-2.12.0/postgres/cast.go
Normal file
132
tools/jet-2.12.0/postgres/cast.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
type cast struct {
|
||||
jet.Cast
|
||||
}
|
||||
|
||||
// CAST function converts an expr (of any type) into later specified datatype.
|
||||
func CAST(expr Expression) *cast {
|
||||
ret := &cast{}
|
||||
ret.Cast = jet.NewCastImpl(expr)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// AS casts expression as castType
|
||||
func (b *cast) AS(castType string) Expression {
|
||||
return b.Cast.AS(castType)
|
||||
}
|
||||
|
||||
// AS_BOOL casts expression as bool type
|
||||
func (b *cast) AS_BOOL() BoolExpression {
|
||||
return BoolExp(b.AS("boolean"))
|
||||
}
|
||||
|
||||
// AS_SMALLINT casts expression as smallint type
|
||||
func (b *cast) AS_SMALLINT() IntegerExpression {
|
||||
return IntExp(b.AS("smallint"))
|
||||
}
|
||||
|
||||
// AS_INTEGER casts expression AS integer type
|
||||
func (b *cast) AS_INTEGER() IntegerExpression {
|
||||
return IntExp(b.AS("integer"))
|
||||
}
|
||||
|
||||
// AS_BIGINT casts expression AS bigint type
|
||||
func (b *cast) AS_BIGINT() IntegerExpression {
|
||||
return IntExp(b.AS("bigint"))
|
||||
}
|
||||
|
||||
// AS_NUMERIC casts expression as numeric type, using precision and optionally scale
|
||||
func (b *cast) AS_NUMERIC(precisionAndScale ...int) FloatExpression {
|
||||
var castArgs string
|
||||
|
||||
var argLen = len(precisionAndScale)
|
||||
if argLen >= 2 {
|
||||
castArgs = fmt.Sprintf("(%d, %d)", precisionAndScale[0], precisionAndScale[1])
|
||||
} else if argLen == 1 {
|
||||
castArgs = fmt.Sprintf("(%d)", precisionAndScale[0])
|
||||
}
|
||||
|
||||
return FloatExp(b.AS("numeric" + castArgs))
|
||||
}
|
||||
|
||||
// AS_REAL casts expression AS real type
|
||||
func (b *cast) AS_REAL() FloatExpression {
|
||||
return FloatExp(b.AS("real"))
|
||||
}
|
||||
|
||||
// AS_DOUBLE casts expression AS double precision type
|
||||
func (b *cast) AS_DOUBLE() FloatExpression {
|
||||
return FloatExp(b.AS("double precision"))
|
||||
}
|
||||
|
||||
// AS_TEXT casts expression AS text type
|
||||
func (b *cast) AS_TEXT() StringExpression {
|
||||
return StringExp(b.AS("text"))
|
||||
}
|
||||
|
||||
// AS_CHAR casts expression AS a character type
|
||||
func (b *cast) AS_CHAR(length ...int) StringExpression {
|
||||
if len(length) > 0 {
|
||||
return StringExp(b.AS("char(" + strconv.Itoa(length[0]) + ")"))
|
||||
}
|
||||
|
||||
return StringExp(b.AS("char"))
|
||||
}
|
||||
|
||||
// AS_VARCHAR casts expression AS a character varying type
|
||||
func (b *cast) AS_VARCHAR(length ...int) StringExpression {
|
||||
if len(length) > 0 {
|
||||
return StringExp(b.AS("varchar(" + strconv.Itoa(length[0]) + ")"))
|
||||
}
|
||||
|
||||
return StringExp(b.AS("varchar"))
|
||||
}
|
||||
|
||||
// AS_DATE casts expression AS date type
|
||||
func (b *cast) AS_DATE() DateExpression {
|
||||
return DateExp(b.AS("date"))
|
||||
}
|
||||
|
||||
// AS_DECIMAL casts expression AS date type
|
||||
func (b *cast) AS_DECIMAL() FloatExpression {
|
||||
return FloatExp(b.AS("decimal"))
|
||||
}
|
||||
|
||||
// AS_BYTEA casts expression AS text type
|
||||
func (b *cast) AS_BYTEA() StringExpression {
|
||||
return StringExp(b.AS("bytea"))
|
||||
}
|
||||
|
||||
// AS_TIME casts expression AS date type
|
||||
func (b *cast) AS_TIME() TimeExpression {
|
||||
return TimeExp(b.AS("time without time zone"))
|
||||
}
|
||||
|
||||
// AS_TIMEZ casts expression AS time with time timezone type
|
||||
func (b *cast) AS_TIMEZ() TimezExpression {
|
||||
return TimezExp(b.AS("time with time zone"))
|
||||
}
|
||||
|
||||
// AS_TIMESTAMP casts expression AS timestamp type
|
||||
func (b *cast) AS_TIMESTAMP() TimestampExpression {
|
||||
return TimestampExp(b.AS("timestamp without time zone"))
|
||||
}
|
||||
|
||||
// AS_TIMESTAMPZ casts expression AS timestamp with timezone type
|
||||
func (b *cast) AS_TIMESTAMPZ() TimestampzExpression {
|
||||
return TimestampzExp(b.AS("timestamp with time zone"))
|
||||
}
|
||||
|
||||
// AS_INTERVAL casts expression AS interval type
|
||||
func (b *cast) AS_INTERVAL() IntervalExpression {
|
||||
return IntervalExp(b.AS("interval"))
|
||||
}
|
||||
71
tools/jet-2.12.0/postgres/cast_test.go
Normal file
71
tools/jet-2.12.0/postgres/cast_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExpressionCAST_AS(t *testing.T) {
|
||||
assertSerialize(t, CAST(Int(11)).AS("text"), `$1::text`, int64(11))
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_BOOL(t *testing.T) {
|
||||
assertSerialize(t, CAST(Int(1)).AS_BOOL(), "$1::boolean", int64(1))
|
||||
assertSerialize(t, CAST(table2Col3).AS_BOOL(), "table2.col3::boolean")
|
||||
assertSerialize(t, CAST(table2Col3.ADD(table2Col3)).AS_BOOL(), "(table2.col3 + table2.col3)::boolean")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_SMALLINT(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_SMALLINT(), "table2.col3::smallint")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_INTEGER(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_INTEGER(), "table2.col3::integer")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_BIGINT(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_BIGINT(), "table2.col3::bigint")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_NUMERIC(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_NUMERIC(11, 11), "table2.col3::numeric(11, 11)")
|
||||
assertSerialize(t, CAST(table2Col3).AS_NUMERIC(11), "table2.col3::numeric(11)")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_REAL(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_REAL(), "table2.col3::real")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_DOUBLE(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_DOUBLE(), "table2.col3::double precision")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_TEXT(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_TEXT(), "table2.col3::text")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_DATE(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_DATE(), "table2.col3::date")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_TIME(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_TIME(), "table2.col3::time without time zone")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_TIMEZ(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_TIMEZ(), "table2.col3::time with time zone")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_TIMESTAMP(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_TIMESTAMP(), "table2.col3::timestamp without time zone")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_TIMESTAMPZ(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2Col3).AS_TIMESTAMPZ(), "table2.col3::timestamp with time zone")
|
||||
}
|
||||
|
||||
func TestExpressionCAST_AS_INTERVAL(t *testing.T) {
|
||||
assertSerialize(t, CAST(table2ColTimez).AS_INTERVAL(), "table2.col_timez::interval")
|
||||
assertSerialize(t, CAST(Time(20, 11, 10)).AS_INTERVAL(), "$1::time without time zone::interval", "20:11:10")
|
||||
assertSerialize(t, table2ColDate.SUB(CAST(Time(20, 11, 10)).AS_INTERVAL()),
|
||||
"(table2.col_date - $1::time without time zone::interval)", "20:11:10")
|
||||
}
|
||||
70
tools/jet-2.12.0/postgres/clause.go
Normal file
70
tools/jet-2.12.0/postgres/clause.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
"github.com/go-jet/jet/v2/internal/utils/is"
|
||||
)
|
||||
|
||||
type onConflict interface {
|
||||
ON_CONSTRAINT(name string) conflictTarget
|
||||
WHERE(indexPredicate BoolExpression) conflictTarget
|
||||
conflictTarget
|
||||
}
|
||||
|
||||
type conflictTarget interface {
|
||||
DO_NOTHING() InsertStatement
|
||||
DO_UPDATE(action conflictAction) InsertStatement
|
||||
}
|
||||
|
||||
type onConflictClause struct {
|
||||
insertStatement InsertStatement
|
||||
constraint string
|
||||
indexExpressions []jet.ColumnExpression
|
||||
whereClause jet.ClauseWhere
|
||||
do jet.Serializer
|
||||
}
|
||||
|
||||
func (o *onConflictClause) ON_CONSTRAINT(name string) conflictTarget {
|
||||
o.constraint = name
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *onConflictClause) WHERE(indexPredicate BoolExpression) conflictTarget {
|
||||
o.whereClause.Condition = indexPredicate
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *onConflictClause) DO_NOTHING() InsertStatement {
|
||||
o.do = jet.Keyword("DO NOTHING")
|
||||
return o.insertStatement
|
||||
}
|
||||
|
||||
func (o *onConflictClause) DO_UPDATE(action conflictAction) InsertStatement {
|
||||
o.do = action
|
||||
return o.insertStatement
|
||||
}
|
||||
|
||||
func (o *onConflictClause) Serialize(statementType jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||
if is.Nil(o.do) {
|
||||
return
|
||||
}
|
||||
|
||||
out.NewLine()
|
||||
out.WriteString("ON CONFLICT")
|
||||
if len(o.indexExpressions) > 0 {
|
||||
out.WriteString("(")
|
||||
jet.SerializeColumnExpressions(o.indexExpressions, statementType, out, jet.ShortName)
|
||||
out.WriteString(")")
|
||||
}
|
||||
|
||||
if o.constraint != "" {
|
||||
out.WriteString("ON CONSTRAINT")
|
||||
out.WriteString(o.constraint)
|
||||
}
|
||||
|
||||
o.whereClause.Serialize(statementType, out, jet.SkipNewLine, jet.ShortName)
|
||||
|
||||
out.IncreaseIdent(7)
|
||||
jet.Serialize(o.do, statementType, out)
|
||||
out.DecreaseIdent(7)
|
||||
}
|
||||
36
tools/jet-2.12.0/postgres/clause_test.go
Normal file
36
tools/jet-2.12.0/postgres/clause_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package postgres
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestOnConflict(t *testing.T) {
|
||||
|
||||
assertClauseSerialize(t, &onConflictClause{}, "")
|
||||
|
||||
onConflict := &onConflictClause{}
|
||||
onConflict.DO_NOTHING()
|
||||
assertClauseSerialize(t, onConflict, `
|
||||
ON CONFLICT DO NOTHING`)
|
||||
|
||||
onConflict = &onConflictClause{indexExpressions: ColumnList{table1ColBool}}
|
||||
onConflict.DO_NOTHING()
|
||||
assertClauseSerialize(t, onConflict, `
|
||||
ON CONFLICT (col_bool) DO NOTHING`)
|
||||
|
||||
onConflict = &onConflictClause{indexExpressions: ColumnList{table1ColBool}}
|
||||
onConflict.ON_CONSTRAINT("table_pkey").DO_NOTHING()
|
||||
assertClauseSerialize(t, onConflict, `
|
||||
ON CONFLICT (col_bool) ON CONSTRAINT table_pkey DO NOTHING`)
|
||||
|
||||
onConflict = &onConflictClause{indexExpressions: ColumnList{table1ColBool, table2ColFloat}}
|
||||
onConflict.WHERE(table2ColFloat.ADD(table1ColInt).GT(table1ColFloat)).
|
||||
DO_UPDATE(
|
||||
SET(table1ColBool.SET(Bool(true)),
|
||||
table1ColInt.SET(Int(11))).
|
||||
WHERE(table2ColFloat.GT(Float(11.1))),
|
||||
)
|
||||
assertClauseSerialize(t, onConflict, `
|
||||
ON CONFLICT (col_bool, col_float) WHERE (col_float + col_int) > col_float DO UPDATE
|
||||
SET col_bool = $1::boolean,
|
||||
col_int = $2
|
||||
WHERE table2.col_float > $3`)
|
||||
}
|
||||
140
tools/jet-2.12.0/postgres/columns.go
Normal file
140
tools/jet-2.12.0/postgres/columns.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
// Column is common column interface for all types of columns.
|
||||
type Column = jet.ColumnExpression
|
||||
|
||||
// ColumnList function returns list of columns that be used as projection or column list for UPDATE and INSERT statement.
|
||||
type ColumnList = jet.ColumnList
|
||||
|
||||
// ColumnBool is interface for SQL boolean columns.
|
||||
type ColumnBool = jet.ColumnBool
|
||||
|
||||
// BoolColumn creates named bool column.
|
||||
var BoolColumn = jet.BoolColumn
|
||||
|
||||
// ColumnString is interface for SQL text, character, character varying
|
||||
// bytea, uuid columns and enums types.
|
||||
type ColumnString = jet.ColumnString
|
||||
|
||||
// StringColumn creates named string column.
|
||||
var StringColumn = jet.StringColumn
|
||||
|
||||
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
||||
type ColumnInteger = jet.ColumnInteger
|
||||
|
||||
// IntegerColumn creates named integer column.
|
||||
var IntegerColumn = jet.IntegerColumn
|
||||
|
||||
// ColumnFloat is interface for SQL real, numeric, decimal or double precision column.
|
||||
type ColumnFloat = jet.ColumnFloat
|
||||
|
||||
// FloatColumn creates named float column.
|
||||
var FloatColumn = jet.FloatColumn
|
||||
|
||||
// ColumnDate is interface of SQL date columns.
|
||||
type ColumnDate = jet.ColumnDate
|
||||
|
||||
// DateColumn creates named date column.
|
||||
var DateColumn = jet.DateColumn
|
||||
|
||||
// ColumnTime is interface for SQL time column.
|
||||
type ColumnTime = jet.ColumnTime
|
||||
|
||||
// TimeColumn creates named time column
|
||||
var TimeColumn = jet.TimeColumn
|
||||
|
||||
// ColumnTimez is interface of SQL time with time zone columns.
|
||||
type ColumnTimez = jet.ColumnTimez
|
||||
|
||||
// TimezColumn creates named time with time zone column.
|
||||
var TimezColumn = jet.TimezColumn
|
||||
|
||||
// ColumnTimestamp is interface of SQL timestamp columns.
|
||||
type ColumnTimestamp = jet.ColumnTimestamp
|
||||
|
||||
// TimestampColumn creates named timestamp column
|
||||
var TimestampColumn = jet.TimestampColumn
|
||||
|
||||
// ColumnTimestampz is interface of SQL timestamp with timezone columns.
|
||||
type ColumnTimestampz = jet.ColumnTimestampz
|
||||
|
||||
// TimestampzColumn creates named timestamp with time zone column.
|
||||
var TimestampzColumn = jet.TimestampzColumn
|
||||
|
||||
// ColumnDateRange is interface of SQL date range column
|
||||
type ColumnDateRange = jet.ColumnRange[DateExpression]
|
||||
|
||||
// DateRangeColumn creates named range with range column
|
||||
var DateRangeColumn = jet.RangeColumn[DateExpression]
|
||||
|
||||
// ColumnNumericRange is interface of SQL numeric range column
|
||||
type ColumnNumericRange = jet.ColumnRange[NumericExpression]
|
||||
|
||||
// NumericRangeColumn creates named range with range column
|
||||
var NumericRangeColumn = jet.RangeColumn[NumericExpression]
|
||||
|
||||
// ColumnTimestampRange is interface of SQL timestamp range column
|
||||
type ColumnTimestampRange = jet.ColumnRange[TimestampExpression]
|
||||
|
||||
// TimestampRangeColumn creates named range with range column
|
||||
var TimestampRangeColumn = jet.RangeColumn[TimestampExpression]
|
||||
|
||||
// ColumnTimestampzRange is interface of SQL timestamp range column
|
||||
type ColumnTimestampzRange = jet.ColumnRange[TimestampzExpression]
|
||||
|
||||
// TimestampzRangeColumn creates named range with range column
|
||||
var TimestampzRangeColumn = jet.RangeColumn[TimestampzExpression]
|
||||
|
||||
// ColumnInt4Range is interface of SQL int4 range column
|
||||
type ColumnInt4Range jet.ColumnRange[jet.Int4Expression]
|
||||
|
||||
// Int4RangeColumn creates named range with range column
|
||||
var Int4RangeColumn = jet.RangeColumn[jet.Int4Expression]
|
||||
|
||||
// ColumnInt8Range is interface of SQL int8 range column
|
||||
type ColumnInt8Range jet.ColumnRange[jet.Int8Expression]
|
||||
|
||||
// Int8RangeColumn creates named range with range column
|
||||
var Int8RangeColumn = jet.RangeColumn[jet.Int8Expression]
|
||||
|
||||
//------------------------------------------------------//
|
||||
|
||||
// ColumnInterval is interface of PostgreSQL interval columns.
|
||||
type ColumnInterval interface {
|
||||
IntervalExpression
|
||||
jet.Column
|
||||
|
||||
From(subQuery SelectTable) ColumnInterval
|
||||
SET(intervalExp IntervalExpression) ColumnAssigment
|
||||
}
|
||||
|
||||
//------------------------------------------------------//
|
||||
|
||||
type intervalColumnImpl struct {
|
||||
jet.ColumnExpressionImpl
|
||||
intervalInterfaceImpl
|
||||
}
|
||||
|
||||
func (i *intervalColumnImpl) SET(intervalExp IntervalExpression) ColumnAssigment {
|
||||
return jet.NewColumnAssignment(i, intervalExp)
|
||||
}
|
||||
|
||||
func (i *intervalColumnImpl) From(subQuery SelectTable) ColumnInterval {
|
||||
newIntervalColumn := IntervalColumn(i.Name())
|
||||
jet.SetTableName(newIntervalColumn, i.TableName())
|
||||
jet.SetSubQuery(newIntervalColumn, subQuery)
|
||||
|
||||
return newIntervalColumn
|
||||
}
|
||||
|
||||
// IntervalColumn creates named interval column.
|
||||
func IntervalColumn(name string) ColumnInterval {
|
||||
intervalColumn := &intervalColumnImpl{}
|
||||
intervalColumn.ColumnExpressionImpl = jet.NewColumnImpl(name, "", intervalColumn)
|
||||
intervalColumn.intervalInterfaceImpl.parent = intervalColumn
|
||||
return intervalColumn
|
||||
}
|
||||
20
tools/jet-2.12.0/postgres/columns_test.go
Normal file
20
tools/jet-2.12.0/postgres/columns_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewIntervalColumn(t *testing.T) {
|
||||
subQuery := SELECT(Int(1)).AsTable("sub_query")
|
||||
|
||||
subQueryIntervalColumn := IntervalColumn("col_interval").From(subQuery)
|
||||
assertSerialize(t, subQueryIntervalColumn, `sub_query.col_interval`)
|
||||
assertSerialize(t, subQueryIntervalColumn.EQ(INTERVAL(2, HOUR, 10, MINUTE)),
|
||||
`(sub_query.col_interval = INTERVAL '2 HOUR 10 MINUTE')`)
|
||||
assertProjectionSerialize(t, subQueryIntervalColumn, `sub_query.col_interval AS "col_interval"`)
|
||||
|
||||
subQueryIntervalColumn2 := table1ColInterval.From(subQuery)
|
||||
assertSerialize(t, subQueryIntervalColumn2, `sub_query."table1.col_interval"`)
|
||||
assertSerialize(t, subQueryIntervalColumn2.EQ(INTERVAL(1, DAY)), `(sub_query."table1.col_interval" = INTERVAL '1 DAY')`)
|
||||
assertProjectionSerialize(t, subQueryIntervalColumn2, `sub_query."table1.col_interval" AS "table1.col_interval"`)
|
||||
}
|
||||
30
tools/jet-2.12.0/postgres/conflict_action.go
Normal file
30
tools/jet-2.12.0/postgres/conflict_action.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
type conflictAction interface {
|
||||
jet.Serializer
|
||||
WHERE(condition BoolExpression) conflictAction
|
||||
}
|
||||
|
||||
// SET creates conflict action for ON_CONFLICT clause
|
||||
func SET(assigments ...ColumnAssigment) conflictAction {
|
||||
conflictAction := updateConflictActionImpl{}
|
||||
conflictAction.doUpdate = jet.KeywordClause{Keyword: "DO UPDATE"}
|
||||
conflictAction.Serializer = jet.NewSerializerClauseImpl(&conflictAction.doUpdate, &conflictAction.set, &conflictAction.where)
|
||||
conflictAction.set = assigments
|
||||
return &conflictAction
|
||||
}
|
||||
|
||||
type updateConflictActionImpl struct {
|
||||
jet.Serializer
|
||||
|
||||
doUpdate jet.KeywordClause
|
||||
set jet.SetClauseNew
|
||||
where jet.ClauseWhere
|
||||
}
|
||||
|
||||
func (u *updateConflictActionImpl) WHERE(condition BoolExpression) conflictAction {
|
||||
u.where.Condition = condition
|
||||
return u
|
||||
}
|
||||
51
tools/jet-2.12.0/postgres/delete_statement.go
Normal file
51
tools/jet-2.12.0/postgres/delete_statement.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// DeleteStatement is interface for PostgreSQL DELETE statement
|
||||
type DeleteStatement interface {
|
||||
jet.SerializerStatement
|
||||
|
||||
USING(tables ...ReadableTable) DeleteStatement
|
||||
WHERE(expression BoolExpression) DeleteStatement
|
||||
RETURNING(projections ...jet.Projection) DeleteStatement
|
||||
}
|
||||
|
||||
type deleteStatementImpl struct {
|
||||
jet.SerializerStatement
|
||||
|
||||
Delete jet.ClauseDelete
|
||||
Using jet.ClauseFrom
|
||||
Where jet.ClauseWhere
|
||||
Returning jet.ClauseReturning
|
||||
}
|
||||
|
||||
func newDeleteStatement(table WritableTable) DeleteStatement {
|
||||
newDelete := &deleteStatementImpl{}
|
||||
newDelete.SerializerStatement = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete,
|
||||
&newDelete.Delete,
|
||||
&newDelete.Using,
|
||||
&newDelete.Where,
|
||||
&newDelete.Returning)
|
||||
|
||||
newDelete.Delete.Table = table
|
||||
newDelete.Using.Name = "USING"
|
||||
newDelete.Where.Mandatory = true
|
||||
|
||||
return newDelete
|
||||
}
|
||||
|
||||
func (d *deleteStatementImpl) USING(tables ...ReadableTable) DeleteStatement {
|
||||
d.Using.Tables = readableTablesToSerializerList(tables)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
||||
d.Where.Condition = expression
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *deleteStatementImpl) RETURNING(projections ...jet.Projection) DeleteStatement {
|
||||
d.Returning.ProjectionList = projections
|
||||
return d
|
||||
}
|
||||
25
tools/jet-2.12.0/postgres/delete_statement_test.go
Normal file
25
tools/jet-2.12.0/postgres/delete_statement_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeleteUnconditionally(t *testing.T) {
|
||||
assertStatementSqlErr(t, table1.DELETE(), `jet: WHERE clause not set`)
|
||||
assertStatementSqlErr(t, table1.DELETE().WHERE(nil), `jet: WHERE clause not set`)
|
||||
}
|
||||
|
||||
func TestDeleteWithWhere(t *testing.T) {
|
||||
assertStatementSql(t, table1.DELETE().WHERE(table1Col1.EQ(Int(1))), `
|
||||
DELETE FROM db.table1
|
||||
WHERE table1.col1 = $1;
|
||||
`, int64(1))
|
||||
}
|
||||
|
||||
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
||||
assertStatementSql(t, table1.DELETE().WHERE(table1Col1.EQ(Int(1))).RETURNING(table1Col1), `
|
||||
DELETE FROM db.table1
|
||||
WHERE table1.col1 = $1
|
||||
RETURNING table1.col1 AS "table1.col1";
|
||||
`, int64(1))
|
||||
}
|
||||
193
tools/jet-2.12.0/postgres/dialect.go
Normal file
193
tools/jet-2.12.0/postgres/dialect.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Dialect is implementation of postgres dialect for SQL Builder serialisation.
|
||||
var Dialect = newDialect()
|
||||
|
||||
func newDialect() jet.Dialect {
|
||||
|
||||
operatorSerializeOverrides := map[string]jet.SerializeOverride{}
|
||||
operatorSerializeOverrides[jet.StringRegexpLikeOperator] = postgresREGEXPLIKEoperator
|
||||
operatorSerializeOverrides[jet.StringNotRegexpLikeOperator] = postgresNOTREGEXPLIKEoperator
|
||||
operatorSerializeOverrides["CAST"] = postgresCAST
|
||||
|
||||
dialectParams := jet.DialectParams{
|
||||
Name: "PostgreSQL",
|
||||
PackageName: "postgres",
|
||||
OperatorSerializeOverrides: operatorSerializeOverrides,
|
||||
AliasQuoteChar: '"',
|
||||
IdentifierQuoteChar: '"',
|
||||
ArgumentPlaceholder: func(ord int) string {
|
||||
return "$" + strconv.Itoa(ord)
|
||||
},
|
||||
ReservedWords: reservedWords,
|
||||
ValuesDefaultColumnName: func(index int) string {
|
||||
return fmt.Sprintf("column%d", index+1)
|
||||
},
|
||||
}
|
||||
|
||||
return jet.NewDialect(dialectParams)
|
||||
}
|
||||
|
||||
func postgresCAST(expressions ...jet.Serializer) jet.SerializerFunc {
|
||||
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||
if len(expressions) < 2 {
|
||||
panic("jet: invalid number of expressions for operator")
|
||||
}
|
||||
|
||||
expression := expressions[0]
|
||||
|
||||
litExpr, ok := expressions[1].(jet.LiteralExpression)
|
||||
|
||||
if !ok {
|
||||
panic("jet: cast invalid cast type")
|
||||
}
|
||||
|
||||
castType, ok := litExpr.Value().(string)
|
||||
|
||||
if !ok {
|
||||
panic("jet: cast type is not string")
|
||||
}
|
||||
|
||||
jet.Serialize(expression, statement, out, options...)
|
||||
out.WriteString("::" + castType)
|
||||
}
|
||||
}
|
||||
|
||||
func postgresREGEXPLIKEoperator(expressions ...jet.Serializer) jet.SerializerFunc {
|
||||
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||
if len(expressions) < 2 {
|
||||
panic("jet: invalid number of expressions for operator")
|
||||
}
|
||||
|
||||
jet.Serialize(expressions[0], statement, out, options...)
|
||||
|
||||
caseSensitive := false
|
||||
|
||||
if len(expressions) >= 3 {
|
||||
if stringLiteral, ok := expressions[2].(jet.LiteralExpression); ok {
|
||||
caseSensitive = stringLiteral.Value().(bool)
|
||||
}
|
||||
}
|
||||
|
||||
if caseSensitive {
|
||||
out.WriteString("~")
|
||||
} else {
|
||||
out.WriteString("~*")
|
||||
}
|
||||
|
||||
jet.Serialize(expressions[1], statement, out, options...)
|
||||
}
|
||||
}
|
||||
|
||||
func postgresNOTREGEXPLIKEoperator(expressions ...jet.Serializer) jet.SerializerFunc {
|
||||
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||
if len(expressions) < 2 {
|
||||
panic("jet: invalid number of expressions for operator")
|
||||
}
|
||||
|
||||
jet.Serialize(expressions[0], statement, out, options...)
|
||||
|
||||
caseSensitive := false
|
||||
|
||||
if len(expressions) >= 3 {
|
||||
if stringLiteral, ok := expressions[2].(jet.LiteralExpression); ok {
|
||||
caseSensitive = stringLiteral.Value().(bool)
|
||||
}
|
||||
}
|
||||
|
||||
if caseSensitive {
|
||||
out.WriteString("!~")
|
||||
} else {
|
||||
out.WriteString("!~*")
|
||||
}
|
||||
|
||||
jet.Serialize(expressions[1], statement, out, options...)
|
||||
}
|
||||
}
|
||||
|
||||
var reservedWords = []string{
|
||||
"ALL",
|
||||
"ANALYSE",
|
||||
"ANALYZE",
|
||||
"AND",
|
||||
"ANY",
|
||||
"ARRAY",
|
||||
"AS",
|
||||
"ASC",
|
||||
"ASYMMETRIC",
|
||||
"BOTH",
|
||||
"CASE",
|
||||
"CAST",
|
||||
"CHECK",
|
||||
"COLLATE",
|
||||
"COLUMN",
|
||||
"CONSTRAINT",
|
||||
"CREATE",
|
||||
"CURRENT_CATALOG",
|
||||
"CURRENT_DATE",
|
||||
"CURRENT_ROLE",
|
||||
"CURRENT_TIME",
|
||||
"CURRENT_TIMESTAMP",
|
||||
"CURRENT_USER",
|
||||
"DEFAULT",
|
||||
"DEFERRABLE",
|
||||
"DESC",
|
||||
"DISTINCT",
|
||||
"DO",
|
||||
"ELSE",
|
||||
"END",
|
||||
"EXCEPT",
|
||||
"FALSE",
|
||||
"FETCH",
|
||||
"FOR",
|
||||
"FOREIGN",
|
||||
"FROM",
|
||||
"GRANT",
|
||||
"GROUP",
|
||||
"HAVING",
|
||||
"IN",
|
||||
"INITIALLY",
|
||||
"INTERSECT",
|
||||
"INTO",
|
||||
"LATERAL",
|
||||
"LEADING",
|
||||
"LIMIT",
|
||||
"LOCALTIME",
|
||||
"LOCALTIMESTAMP",
|
||||
"NOT",
|
||||
"NULL",
|
||||
"OFFSET",
|
||||
"ON",
|
||||
"ONLY",
|
||||
"OR",
|
||||
"ORDER",
|
||||
"PLACING",
|
||||
"PRIMARY",
|
||||
"REFERENCES",
|
||||
"RETURNING",
|
||||
"RIGHT",
|
||||
"SELECT",
|
||||
"SESSION_USER",
|
||||
"SOME",
|
||||
"SYMMETRIC",
|
||||
"TABLE",
|
||||
"THEN",
|
||||
"TO",
|
||||
"TRAILING",
|
||||
"TRUE",
|
||||
"UNION",
|
||||
"UNIQUE",
|
||||
"USER",
|
||||
"USING",
|
||||
"VARIADIC",
|
||||
"WHEN",
|
||||
"WHERE",
|
||||
"WINDOW",
|
||||
"WITH",
|
||||
}
|
||||
88
tools/jet-2.12.0/postgres/dialect_test.go
Normal file
88
tools/jet-2.12.0/postgres/dialect_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package postgres
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestString_REGEXP_LIKE_operator(t *testing.T) {
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(table2ColStr), "(table3.col2 ~* table2.col_str)")
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN")), "(table3.col2 ~* $1::text)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), false), "(table3.col2 ~* $1::text)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), true), "(table3.col2 ~ $1::text)", "JOHN")
|
||||
}
|
||||
|
||||
func TestString_NOT_REGEXP_LIKE_operator(t *testing.T) {
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(table2ColStr), "(table3.col2 !~* table2.col_str)")
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN")), "(table3.col2 !~* $1::text)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), false), "(table3.col2 !~* $1::text)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), true), "(table3.col2 !~ $1::text)", "JOHN")
|
||||
}
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
assertSerialize(t, EXISTS(
|
||||
table2.
|
||||
SELECT(Int(1)).
|
||||
WHERE(table1Col1.EQ(table2Col3)),
|
||||
),
|
||||
`(EXISTS (
|
||||
SELECT $1
|
||||
FROM db.table2
|
||||
WHERE table1.col1 = table2.col3
|
||||
))`, int64(1))
|
||||
|
||||
assertSerialize(t, EXISTS(
|
||||
SELECT(Int(1)),
|
||||
).EQ(Bool(true)),
|
||||
`((EXISTS (
|
||||
SELECT $1
|
||||
)) = $2::boolean)`, int64(1), true)
|
||||
|
||||
assertProjectionSerialize(t, EXISTS(
|
||||
SELECT(Int(1)),
|
||||
).AS("exists"),
|
||||
`(EXISTS (
|
||||
SELECT $1
|
||||
)) AS "exists"`, int64(1))
|
||||
}
|
||||
|
||||
func TestIN(t *testing.T) {
|
||||
|
||||
assertSerialize(t, Float(1.11).IN(table1.SELECT(table1Col1)),
|
||||
`($1 IN ((
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
)))`, float64(1.11))
|
||||
|
||||
assertSerialize(t, ROW(Int(12), table1Col1).IN(table2.SELECT(table2Col3, table3Col1)),
|
||||
`(ROW($1, table1.col1) IN ((
|
||||
SELECT table2.col3 AS "table2.col3",
|
||||
table3.col1 AS "table3.col1"
|
||||
FROM db.table2
|
||||
)))`, int64(12))
|
||||
}
|
||||
|
||||
func TestNOT_IN(t *testing.T) {
|
||||
|
||||
assertSerialize(t, Float(1.11).NOT_IN(table1.SELECT(table1Col1)),
|
||||
`($1 NOT IN ((
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
)))`, float64(1.11))
|
||||
|
||||
assertSerialize(t, ROW(Int(12), table1Col1).NOT_IN(table2.SELECT(table2Col3, table3Col1)),
|
||||
`(ROW($1, table1.col1) NOT IN ((
|
||||
SELECT table2.col3 AS "table2.col3",
|
||||
table3.col1 AS "table3.col1"
|
||||
FROM db.table2
|
||||
)))`, int64(12))
|
||||
}
|
||||
|
||||
func TestReservedWordEscaped(t *testing.T) {
|
||||
var table1ColUser = IntervalColumn("user")
|
||||
var table1ColVariadic = IntervalColumn("VARIADIC")
|
||||
var table1ColProcedure = IntervalColumn("procedure")
|
||||
|
||||
_ = NewTable("db", "table1", "", table1ColUser, table1ColVariadic, table1ColProcedure)
|
||||
|
||||
assertSerialize(t, table1ColUser, `table1."user"`)
|
||||
assertSerialize(t, table1ColVariadic, `table1."VARIADIC"`)
|
||||
assertSerialize(t, table1ColProcedure, `table1.procedure`)
|
||||
}
|
||||
161
tools/jet-2.12.0/postgres/expressions.go
Normal file
161
tools/jet-2.12.0/postgres/expressions.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// Expression is common interface for all expressions.
|
||||
// Can be Bool, Int, Float, String, Date, Time, Timez, Timestamp or Timestampz expressions.
|
||||
type Expression = jet.Expression
|
||||
|
||||
// BoolExpression interface
|
||||
type BoolExpression = jet.BoolExpression
|
||||
|
||||
// StringExpression interface
|
||||
type StringExpression = jet.StringExpression
|
||||
|
||||
// NumericExpression interface
|
||||
type NumericExpression = jet.NumericExpression
|
||||
|
||||
// IntegerExpression interface
|
||||
type IntegerExpression = jet.IntegerExpression
|
||||
|
||||
// FloatExpression is interface
|
||||
type FloatExpression = jet.FloatExpression
|
||||
|
||||
// TimeExpression interface
|
||||
type TimeExpression = jet.TimeExpression
|
||||
|
||||
// TimezExpression interface for 'time with time zone' types
|
||||
type TimezExpression = jet.TimezExpression
|
||||
|
||||
// DateExpression is interface for date types
|
||||
type DateExpression = jet.DateExpression
|
||||
|
||||
// TimestampExpression interface
|
||||
type TimestampExpression = jet.TimestampExpression
|
||||
|
||||
// TimestampzExpression interface
|
||||
type TimestampzExpression = jet.TimestampzExpression
|
||||
|
||||
// RowExpression interface
|
||||
type RowExpression = jet.RowExpression
|
||||
|
||||
// DateRange Expression interface
|
||||
type DateRange = jet.Range[DateExpression]
|
||||
|
||||
// TimestampRange Expression interface
|
||||
type TimestampRange = jet.Range[TimestampExpression]
|
||||
|
||||
// TimestampzRange Expression interface
|
||||
type TimestampzRange = jet.Range[TimestampzExpression]
|
||||
|
||||
// NumericRange Expression interface
|
||||
type NumericRange = jet.Range[NumericExpression]
|
||||
|
||||
// Int4Range Expression interface
|
||||
type Int4Range = jet.Range[IntegerExpression]
|
||||
|
||||
// Int8Range Expression interface
|
||||
type Int8Range = jet.Range[IntegerExpression]
|
||||
|
||||
// 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.
|
||||
var BoolExp = jet.BoolExp
|
||||
|
||||
// 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.
|
||||
var IntExp = jet.IntExp
|
||||
|
||||
// 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.
|
||||
var FloatExp = jet.FloatExp
|
||||
|
||||
// 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.
|
||||
var TimeExp = jet.TimeExp
|
||||
|
||||
// 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.
|
||||
var StringExp = jet.StringExp
|
||||
|
||||
// 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.
|
||||
var TimezExp = jet.TimezExp
|
||||
|
||||
// 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.
|
||||
var DateExp = jet.DateExp
|
||||
|
||||
// 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.
|
||||
var TimestampExp = jet.TimestampExp
|
||||
|
||||
// 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.
|
||||
var TimestampzExp = jet.TimestampzExp
|
||||
|
||||
// RowExp serves as a wrapper for an arbitrary expression, treating it as a row expression.
|
||||
// This enables the Go compiler to interpret any expression as a row expression
|
||||
// Note: This does not modify the generated SQL builder output by adding a SQL CAST operation.
|
||||
var RowExp = jet.RowExp
|
||||
|
||||
// RangeExp is range expression wrapper around arbitrary expression.
|
||||
// Allows go compiler to see any expression as range expression.
|
||||
// Does not add sql cast to generated sql builder output.
|
||||
var (
|
||||
Int4RangeExp = jet.Int4RangeExp
|
||||
Int8RangeExp = jet.Int8RangeExp
|
||||
NumRangeExp = jet.NumRangeExp
|
||||
DateRangeExp = jet.DateRangeExp
|
||||
TsRangeExp = jet.TsRangeExp
|
||||
TstzRangeExp = jet.TstzRangeExp
|
||||
)
|
||||
|
||||
// CustomExpression is used to define custom expressions.
|
||||
var CustomExpression = jet.CustomExpression
|
||||
|
||||
// Token is used to define custom token in a custom expression.
|
||||
type Token = jet.Token
|
||||
|
||||
// RawArgs is type used to pass optional arguments to Raw method
|
||||
type RawArgs = map[string]interface{}
|
||||
|
||||
// Raw can be used for any unsupported functions, operators or expressions.
|
||||
// For example: Raw("current_database()")
|
||||
// Raw helper methods for each of the postgres types
|
||||
var (
|
||||
Raw = jet.Raw
|
||||
|
||||
RawBool = jet.RawBool
|
||||
RawInt = jet.RawInt
|
||||
RawFloat = jet.RawFloat
|
||||
RawString = jet.RawString
|
||||
RawTime = jet.RawTime
|
||||
RawTimez = jet.RawTimez
|
||||
RawTimestamp = jet.RawTimestamp
|
||||
RawTimestampz = jet.RawTimestampz
|
||||
RawDate = jet.RawDate
|
||||
RawNumRange = jet.RawRange[jet.NumericExpression]
|
||||
RawInt4Range = jet.RawRange[jet.Int4Expression]
|
||||
RawInt8Range = jet.RawRange[jet.Int8Expression]
|
||||
RawTimestampRange = jet.RawRange[jet.TimestampExpression]
|
||||
RawTimestampzRange = jet.RawRange[jet.TimestampzExpression]
|
||||
RawDateRange = jet.RawRange[jet.DateExpression]
|
||||
)
|
||||
|
||||
// Func can be used to call custom or unsupported database functions.
|
||||
var Func = jet.Func
|
||||
|
||||
// NewEnumValue creates new named enum value
|
||||
var NewEnumValue = jet.NewEnumValue
|
||||
|
||||
// BinaryOperator can be used to use custom or unsupported operators that take two operands.
|
||||
var BinaryOperator = jet.BinaryOperator
|
||||
79
tools/jet-2.12.0/postgres/expressions_test.go
Normal file
79
tools/jet-2.12.0/postgres/expressions_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRaw(t *testing.T) {
|
||||
assertSerialize(t, Raw("current_database()"), "(current_database())")
|
||||
assertDebugSerialize(t, Raw("current_database()"), "(current_database())")
|
||||
|
||||
assertSerialize(t, Raw(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22}),
|
||||
"($1 + table.colInt + $2)", 11, 22)
|
||||
assertDebugSerialize(t, Raw(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22}),
|
||||
"(11 + table.colInt + 22)")
|
||||
|
||||
assertSerialize(t,
|
||||
Int(700).ADD(RawInt(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22})),
|
||||
"($1 + ($2 + table.colInt + $3))",
|
||||
int64(700), 11, 22)
|
||||
assertDebugSerialize(t,
|
||||
Int(700).ADD(RawInt(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22})),
|
||||
"(700 + (11 + table.colInt + 22))")
|
||||
}
|
||||
|
||||
func TestDuplicateArguments(t *testing.T) {
|
||||
assertSerialize(t, Raw(":arg + table.colInt + :arg", RawArgs{":arg": 11}),
|
||||
"($1 + table.colInt + $1)", 11)
|
||||
assertDebugSerialize(t, Raw(":arg + table.colInt + :arg", RawArgs{":arg": 11}),
|
||||
"(11 + table.colInt + 11)")
|
||||
|
||||
assertSerialize(t, Raw("#age + table.colInt + #year + #age + #year + 11", RawArgs{"#age": 11, "#year": 2000}),
|
||||
"($1 + table.colInt + $2 + $1 + $2 + 11)", 11, 2000)
|
||||
assertDebugSerialize(t, Raw("#age + table.colInt + #year + #age + #year + 11", RawArgs{"#age": 11, "#year": 2000}),
|
||||
"(11 + table.colInt + 2000 + 11 + 2000 + 11)")
|
||||
|
||||
assertSerialize(t, Raw("#1 + all_types.integer + #2 + #1 + #2 + #3 + #4",
|
||||
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}),
|
||||
`($1 + all_types.integer + $2 + $1 + $2 + $3 + $4)`, 11, 22, 33, 44)
|
||||
assertDebugSerialize(t, Raw("#1 + all_types.integer + #2 + #1 + #2 + #3 + #4",
|
||||
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}),
|
||||
`(11 + all_types.integer + 22 + 11 + 22 + 33 + 44)`)
|
||||
}
|
||||
|
||||
func TestRawInvalidArguments(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
require.Equal(t, "jet: named argument 'first_arg' does not appear in raw query", r)
|
||||
}()
|
||||
|
||||
assertSerialize(t, Raw("table.colInt + :second_arg", RawArgs{
|
||||
"first_arg": 11,
|
||||
"second_arg": 22,
|
||||
}), "(table.colInt + $1)", 22)
|
||||
}
|
||||
|
||||
func TestRawHelperMethods(t *testing.T) {
|
||||
assertSerialize(t, RawBool("table.colInt < :float", RawArgs{":float": 11.22}).IS_FALSE(),
|
||||
"(table.colInt < $1) IS FALSE", 11.22)
|
||||
|
||||
assertSerialize(t, RawFloat("table.colInt + :float", RawArgs{":float": 11.22}).EQ(Float(3.14)),
|
||||
"((table.colInt + $1) = $2)", 11.22, 3.14)
|
||||
assertSerialize(t, RawString("table.colStr || str", RawArgs{"str": "doe"}).EQ(String("john doe")),
|
||||
"((table.colStr || $1) = $2::text)", "doe", "john doe")
|
||||
|
||||
now := time.Now()
|
||||
assertSerialize(t, RawTime("table.colTime").EQ(TimeT(now)),
|
||||
"((table.colTime) = $1::time without time zone)", now)
|
||||
assertSerialize(t, RawTimez("table.colTime").EQ(TimezT(now)),
|
||||
"((table.colTime) = $1::time with time zone)", now)
|
||||
assertSerialize(t, RawTimestamp("table.colTimestamp").EQ(TimestampT(now)),
|
||||
"((table.colTimestamp) = $1::timestamp without time zone)", now)
|
||||
assertSerialize(t, RawTimestampz("table.colTimestampz").EQ(TimestampzT(now)),
|
||||
"((table.colTimestampz) = $1::timestamp with time zone)", now)
|
||||
assertSerialize(t, RawDate("table.colDate").EQ(DateT(now)),
|
||||
"((table.colDate) = $1::date)", now)
|
||||
}
|
||||
474
tools/jet-2.12.0/postgres/functions.go
Normal file
474
tools/jet-2.12.0/postgres/functions.go
Normal file
@@ -0,0 +1,474 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
// This functions can be used, instead of its method counterparts, to have a better indentation of a complex condition
|
||||
// in the Go code and in the generated SQL.
|
||||
var (
|
||||
// AND function adds AND operator between expressions.
|
||||
AND = jet.AND
|
||||
// OR function adds OR operator between expressions.
|
||||
OR = jet.OR
|
||||
)
|
||||
|
||||
// ROW function is used to create a tuple value that consists of a set of expressions or column values.
|
||||
func ROW(expressions ...Expression) RowExpression {
|
||||
return jet.ROW(Dialect, expressions...)
|
||||
}
|
||||
|
||||
// ------------------ Mathematical functions ---------------//
|
||||
|
||||
// ABSf calculates absolute value from float expression
|
||||
var ABSf = jet.ABSf
|
||||
|
||||
// ABSi calculates absolute value from int expression
|
||||
var ABSi = jet.ABSi
|
||||
|
||||
// POW calculates power of base with exponent
|
||||
var POW = jet.POW
|
||||
|
||||
// POWER calculates power of base with exponent
|
||||
var POWER = jet.POWER
|
||||
|
||||
// SQRT calculates square root of numeric expression
|
||||
var SQRT = jet.SQRT
|
||||
|
||||
// CBRT calculates cube root of numeric expression
|
||||
var CBRT = jet.CBRT
|
||||
|
||||
// CEIL calculates ceil of float expression
|
||||
var CEIL = jet.CEIL
|
||||
|
||||
// FLOOR calculates floor of float expression
|
||||
var FLOOR = jet.FLOOR
|
||||
|
||||
// ROUND calculates round of a float expressions with optional precision
|
||||
var ROUND = jet.ROUND
|
||||
|
||||
// SIGN returns sign of float expression
|
||||
var SIGN = jet.SIGN
|
||||
|
||||
// TRUNC calculates trunc of float expression with optional precision
|
||||
var TRUNC = jet.TRUNC
|
||||
|
||||
// LN calculates natural algorithm of float expression
|
||||
var LN = jet.LN
|
||||
|
||||
// LOG calculates logarithm of float expression
|
||||
var LOG = jet.LOG
|
||||
|
||||
// ----------------- Aggregate functions -------------------//
|
||||
|
||||
// AVG is aggregate function used to calculate avg value from numeric expression
|
||||
var AVG = jet.AVG
|
||||
|
||||
// BIT_AND is aggregate function used to calculates the bitwise AND of all non-null input values, or null if none.
|
||||
var BIT_AND = jet.BIT_AND
|
||||
|
||||
// BIT_OR is aggregate function used to calculates the bitwise OR of all non-null input values, or null if none.
|
||||
var BIT_OR = jet.BIT_OR
|
||||
|
||||
// BOOL_AND is aggregate function. Returns true if all input values are true, otherwise false
|
||||
var BOOL_AND = jet.BOOL_AND
|
||||
|
||||
// BOOL_OR is aggregate function. Returns true if at least one input value is true, otherwise false
|
||||
var BOOL_OR = jet.BOOL_OR
|
||||
|
||||
// COUNT is aggregate function. Returns number of input rows for which the value of expression is not null.
|
||||
var COUNT = jet.COUNT
|
||||
|
||||
// EVERY is aggregate function. Returns true if all input values are true, otherwise false
|
||||
var EVERY = jet.EVERY
|
||||
|
||||
// MAX is aggregate function. Returns maximum value of expression across all input values
|
||||
var MAX = jet.MAX
|
||||
|
||||
// MAXf is aggregate function. Returns maximum value of float expression across all input values
|
||||
var MAXf = jet.MAXf
|
||||
|
||||
// MAXi is aggregate function. Returns maximum value of int expression across all input values
|
||||
var MAXi = jet.MAXi
|
||||
|
||||
// MIN is aggregate function. Returns minimum value of expression across all input values.
|
||||
var MIN = jet.MIN
|
||||
|
||||
// MINf is aggregate function. Returns minimum value of float expression across all input values
|
||||
var MINf = jet.MINf
|
||||
|
||||
// MINi is aggregate function. Returns minimum value of int expression across all input values
|
||||
var MINi = jet.MINi
|
||||
|
||||
// SUM is aggregate function. Returns sum of all expressions
|
||||
var SUM = jet.SUM
|
||||
|
||||
// SUMf is aggregate function. Returns sum of expression across all float expressions
|
||||
var SUMf = jet.SUMf
|
||||
|
||||
// SUMi is aggregate function. Returns sum of expression across all integer expression.
|
||||
var SUMi = jet.SUMi
|
||||
|
||||
// -------------------- Window functions -----------------------//
|
||||
|
||||
// ROW_NUMBER returns number of the current row within its partition, counting from 1
|
||||
var ROW_NUMBER = jet.ROW_NUMBER
|
||||
|
||||
// RANK of the current row with gaps; same as row_number of its first peer
|
||||
var RANK = jet.RANK
|
||||
|
||||
// DENSE_RANK returns rank of the current row without gaps; this function counts peer groups
|
||||
var DENSE_RANK = jet.DENSE_RANK
|
||||
|
||||
// PERCENT_RANK calculates relative rank of the current row: (rank - 1) / (total partition rows - 1)
|
||||
var PERCENT_RANK = jet.PERCENT_RANK
|
||||
|
||||
// CUME_DIST calculates cumulative distribution: (number of partition rows preceding or peer with current row) / total partition rows
|
||||
var CUME_DIST = jet.CUME_DIST
|
||||
|
||||
// NTILE returns integer ranging from 1 to the argument value, dividing the partition as equally as possible
|
||||
var NTILE = jet.NTILE
|
||||
|
||||
// LAG returns value evaluated at the row that is offset rows before the current row within the partition;
|
||||
// if there is no such row, instead return default (which must be of the same type as value).
|
||||
// Both offset and default are evaluated with respect to the current row.
|
||||
// If omitted, offset defaults to 1 and default to null
|
||||
var LAG = jet.LAG
|
||||
|
||||
// LEAD returns value evaluated at the row that is offset rows after the current row within the partition;
|
||||
// if there is no such row, instead return default (which must be of the same type as value).
|
||||
// Both offset and default are evaluated with respect to the current row.
|
||||
// If omitted, offset defaults to 1 and default to null
|
||||
var LEAD = jet.LEAD
|
||||
|
||||
// FIRST_VALUE returns value evaluated at the row that is the first row of the window frame
|
||||
var FIRST_VALUE = jet.FIRST_VALUE
|
||||
|
||||
// LAST_VALUE returns value evaluated at the row that is the last row of the window frame
|
||||
var LAST_VALUE = jet.LAST_VALUE
|
||||
|
||||
// NTH_VALUE returns value evaluated at the row that is the nth row of the window frame (counting from 1); null if no such row
|
||||
var NTH_VALUE = jet.NTH_VALUE
|
||||
|
||||
//--------------------- String functions ------------------//
|
||||
|
||||
// BIT_LENGTH returns number of bits in string expression
|
||||
var BIT_LENGTH = jet.BIT_LENGTH
|
||||
|
||||
// CHAR_LENGTH returns number of characters in string expression
|
||||
var CHAR_LENGTH = jet.CHAR_LENGTH
|
||||
|
||||
// OCTET_LENGTH returns number of bytes in string expression
|
||||
var OCTET_LENGTH = jet.OCTET_LENGTH
|
||||
|
||||
// LOWER returns string expression in lower case
|
||||
var LOWER = jet.LOWER
|
||||
|
||||
// UPPER returns string expression in upper case
|
||||
var UPPER = jet.UPPER
|
||||
|
||||
// BTRIM removes the longest string consisting only of characters
|
||||
// in characters (a space by default) from the start and end of string
|
||||
var BTRIM = jet.BTRIM
|
||||
|
||||
// LTRIM removes the longest string containing only characters
|
||||
// from characters (a space by default) from the start of string
|
||||
var LTRIM = jet.LTRIM
|
||||
|
||||
// RTRIM removes the longest string containing only characters
|
||||
// from characters (a space by default) from the end of string
|
||||
var RTRIM = jet.RTRIM
|
||||
|
||||
// CHR returns character with the given code.
|
||||
var CHR = jet.CHR
|
||||
|
||||
// CONCAT adds two or more expressions together
|
||||
var CONCAT = func(expressions ...Expression) StringExpression {
|
||||
return jet.CONCAT(explicitLiteralCasts(expressions...)...)
|
||||
}
|
||||
|
||||
// CONCAT_WS adds two or more expressions together with a separator.
|
||||
func CONCAT_WS(separator Expression, expressions ...Expression) StringExpression {
|
||||
return jet.CONCAT_WS(explicitLiteralCast(separator), explicitLiteralCasts(expressions...)...)
|
||||
}
|
||||
|
||||
// CONVERT converts string to dest_encoding. The original encoding is
|
||||
// specified by src_encoding. The string must be valid in this encoding.
|
||||
var CONVERT = jet.CONVERT
|
||||
|
||||
// CONVERT_FROM converts string to the database encoding. The original
|
||||
// encoding is specified by src_encoding. The string must be valid in this encoding.
|
||||
var CONVERT_FROM = jet.CONVERT_FROM
|
||||
|
||||
// CONVERT_TO converts string to dest_encoding.
|
||||
var CONVERT_TO = jet.CONVERT_TO
|
||||
|
||||
// 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.
|
||||
var ENCODE = jet.ENCODE
|
||||
|
||||
// DECODE decodes binary data from textual representation in string.
|
||||
// Options for format are same as in encode.
|
||||
var DECODE = jet.DECODE
|
||||
|
||||
// FORMAT formats a number to a format like "#,###,###.##", rounded to a specified number of decimal places, then it returns the result as a string.
|
||||
func FORMAT(formatStr StringExpression, formatArgs ...Expression) StringExpression {
|
||||
return jet.FORMAT(formatStr, explicitLiteralCasts(formatArgs...)...)
|
||||
}
|
||||
|
||||
// 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.
|
||||
var INITCAP = jet.INITCAP
|
||||
|
||||
// LEFT returns first n characters in the string.
|
||||
// When n is negative, return all but last |n| characters.
|
||||
var LEFT = jet.LEFT
|
||||
|
||||
// RIGHT returns last n characters in the string.
|
||||
// When n is negative, return all but first |n| characters.
|
||||
var RIGHT = jet.RIGHT
|
||||
|
||||
// LENGTH returns number of characters in string with a given encoding
|
||||
var LENGTH = jet.LENGTH
|
||||
|
||||
// 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).
|
||||
var LPAD = jet.LPAD
|
||||
|
||||
// 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.
|
||||
var RPAD = jet.RPAD
|
||||
|
||||
// MD5 calculates the MD5 hash of string, returning the result in hexadecimal
|
||||
var MD5 = jet.MD5
|
||||
|
||||
// REPEAT repeats string the specified number of times
|
||||
var REPEAT = jet.REPEAT
|
||||
|
||||
// REPLACE replaces all occurrences in string of substring from with substring to
|
||||
var REPLACE = jet.REPLACE
|
||||
|
||||
// REVERSE returns reversed string.
|
||||
var REVERSE = jet.REVERSE
|
||||
|
||||
// STRPOS returns location of specified substring (same as position(substring in string),
|
||||
// but note the reversed argument order)
|
||||
var STRPOS = jet.STRPOS
|
||||
|
||||
// SUBSTR extracts substring
|
||||
var SUBSTR = jet.SUBSTR
|
||||
|
||||
// TO_ASCII convert string to ASCII from another encoding
|
||||
var TO_ASCII = jet.TO_ASCII
|
||||
|
||||
// TO_HEX converts number to its equivalent hexadecimal representation
|
||||
var TO_HEX = jet.TO_HEX
|
||||
|
||||
//----------Data Type Formatting Functions ----------------------//
|
||||
|
||||
// LOWER_BOUND returns range expressions lower bound
|
||||
func LOWER_BOUND[T Expression](expression jet.Range[T]) T {
|
||||
return jet.LOWER_BOUND[T](expression)
|
||||
}
|
||||
|
||||
// UPPER_BOUND returns range expressions upper bound
|
||||
func UPPER_BOUND[T Expression](expression jet.Range[T]) T {
|
||||
return jet.UPPER_BOUND[T](expression)
|
||||
}
|
||||
|
||||
//----------Data Type Formatting Functions ----------------------//
|
||||
|
||||
// TO_CHAR converts expression to string with format
|
||||
var TO_CHAR = jet.TO_CHAR
|
||||
|
||||
// TO_DATE converts string to date using format
|
||||
var TO_DATE = jet.TO_DATE
|
||||
|
||||
// TO_NUMBER converts string to numeric using format
|
||||
var TO_NUMBER = jet.TO_NUMBER
|
||||
|
||||
// TO_TIMESTAMP converts string to time stamp with time zone using format
|
||||
var TO_TIMESTAMP = jet.TO_TIMESTAMP
|
||||
|
||||
//----------------- Date/Time Functions and Operators ------------//
|
||||
|
||||
// Additional time unit types for EXTRACT function
|
||||
const (
|
||||
DOW unit = MILLENNIUM + 1 + iota
|
||||
DOY
|
||||
EPOCH
|
||||
ISODOW
|
||||
ISOYEAR
|
||||
JULIAN
|
||||
QUARTER
|
||||
TIMEZONE
|
||||
TIMEZONE_HOUR
|
||||
TIMEZONE_MINUTE
|
||||
)
|
||||
|
||||
// EXTRACT function retrieves subfields such as year or hour from date/time values
|
||||
//
|
||||
// EXTRACT(DAY, User.CreatedAt)
|
||||
func EXTRACT(field unit, from Expression) FloatExpression {
|
||||
return FloatExp(jet.EXTRACT(unitToString(field), from))
|
||||
}
|
||||
|
||||
// CURRENT_DATE returns current date
|
||||
var CURRENT_DATE = jet.CURRENT_DATE
|
||||
|
||||
// CURRENT_TIME returns current time with time zone
|
||||
var CURRENT_TIME = jet.CURRENT_TIME
|
||||
|
||||
// CURRENT_TIMESTAMP returns current timestamp with time zone
|
||||
var CURRENT_TIMESTAMP = jet.CURRENT_TIMESTAMP
|
||||
|
||||
// LOCALTIME returns local time of day using optional precision
|
||||
var LOCALTIME = jet.LOCALTIME
|
||||
|
||||
// LOCALTIMESTAMP returns current date and time using optional precision
|
||||
var LOCALTIMESTAMP = jet.LOCALTIMESTAMP
|
||||
|
||||
// NOW returns current date and time
|
||||
var NOW = jet.NOW
|
||||
|
||||
// DATE_TRUNC returns the truncated date and time using optional time zone.
|
||||
// Use TimestampzExp if you need timestamp with time zone and IntervalExp if you need interval.
|
||||
func DATE_TRUNC(field unit, source Expression, timezone ...string) TimestampExpression {
|
||||
if len(timezone) > 0 {
|
||||
return jet.NewTimestampFunc("DATE_TRUNC", jet.FixedLiteral(unitToString(field)), source, jet.FixedLiteral(timezone[0]))
|
||||
}
|
||||
|
||||
return jet.NewTimestampFunc("DATE_TRUNC", jet.FixedLiteral(unitToString(field)), source)
|
||||
}
|
||||
|
||||
// GENERATE_SERIES generates a series of values from start to stop, with a step size of step.
|
||||
func GENERATE_SERIES(start Expression, stop Expression, step ...Expression) Expression {
|
||||
if len(step) > 0 {
|
||||
return jet.NewFunc("GENERATE_SERIES", []Expression{start, stop, step[0]}, nil)
|
||||
}
|
||||
|
||||
return jet.NewFunc("GENERATE_SERIES", []Expression{start, stop}, nil)
|
||||
}
|
||||
|
||||
// --------------- Conditional Expressions Functions -------------//
|
||||
|
||||
// COALESCE function returns the first of its arguments that is not null.
|
||||
var COALESCE = jet.COALESCE
|
||||
|
||||
// NULLIF function returns a null value if value1 equals value2; otherwise it returns value1.
|
||||
var NULLIF = jet.NULLIF
|
||||
|
||||
// GREATEST selects the largest value from a list of expressions
|
||||
var GREATEST = jet.GREATEST
|
||||
|
||||
// LEAST selects the smallest value from a list of expressions
|
||||
var LEAST = jet.LEAST
|
||||
|
||||
// EXISTS checks for existence of the rows in subQuery
|
||||
var EXISTS = jet.EXISTS
|
||||
|
||||
// CASE create CASE operator with optional list of expressions
|
||||
var CASE = jet.CASE
|
||||
|
||||
func explicitLiteralCasts(expressions ...Expression) []jet.Expression {
|
||||
ret := []jet.Expression{}
|
||||
|
||||
for _, exp := range expressions {
|
||||
ret = append(ret, explicitLiteralCast(exp))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func explicitLiteralCast(expresion Expression) jet.Expression {
|
||||
if _, ok := expresion.(jet.LiteralExpression); !ok {
|
||||
return expresion
|
||||
}
|
||||
|
||||
switch expresion.(type) {
|
||||
case jet.BoolExpression:
|
||||
return CAST(expresion).AS_BOOL()
|
||||
case jet.IntegerExpression:
|
||||
return CAST(expresion).AS_INTEGER()
|
||||
case jet.FloatExpression:
|
||||
return CAST(expresion).AS_NUMERIC()
|
||||
case jet.StringExpression:
|
||||
return CAST(expresion).AS_TEXT()
|
||||
}
|
||||
|
||||
return expresion
|
||||
}
|
||||
|
||||
// MODE computes the most frequent value of the aggregated argument
|
||||
var MODE = jet.MODE
|
||||
|
||||
// PERCENTILE_CONT computes a value corresponding to the specified fraction within the ordered set of
|
||||
// aggregated argument values. This will interpolate between adjacent input items if needed.
|
||||
func PERCENTILE_CONT(fraction FloatExpression) *jet.OrderSetAggregateFunc {
|
||||
return jet.PERCENTILE_CONT(castFloatLiteral(fraction))
|
||||
}
|
||||
|
||||
// PERCENTILE_DISC computes the first value within the ordered set of aggregated argument values whose position
|
||||
// in the ordering equals or exceeds the specified fraction. The aggregated argument must be of a sortable type.
|
||||
func PERCENTILE_DISC(fraction FloatExpression) *jet.OrderSetAggregateFunc {
|
||||
return jet.PERCENTILE_DISC(castFloatLiteral(fraction))
|
||||
}
|
||||
|
||||
func castFloatLiteral(fraction FloatExpression) FloatExpression {
|
||||
if _, ok := fraction.(jet.LiteralExpression); ok {
|
||||
return CAST(fraction).AS_DOUBLE() // to make postgres aware of the type
|
||||
}
|
||||
return fraction
|
||||
}
|
||||
|
||||
// ----------------- Group By operators --------------------------//
|
||||
|
||||
// GROUPING_SETS operator allows grouping of the rows in a table by multiple sets of columns(or expressions) in a single query.
|
||||
// This can be useful when we want to analyze data by different combinations of columns, without having to write separate
|
||||
// queries for each combination. GROUPING_SETS sets of columns are constructed with WRAP method.
|
||||
//
|
||||
// GROUPING_SETS(
|
||||
// WRAP(Inventory.FilmID, Inventory.StoreID),
|
||||
// WRAP(),
|
||||
// ),
|
||||
var GROUPING_SETS = jet.GROUPING_SETS
|
||||
|
||||
// WRAP surrounds a list of expressions or columns with parentheses, producing new row: (expression1, expression2, ...)
|
||||
// The construct (a, b) is normally recognized in expressions as a row constructor. WRAP and ROW methods behave exactly the same,
|
||||
// except when used in GROUPING_SETS and VALUES. In these contexts, WRAP must be used instead of ROW.
|
||||
func WRAP(expressions ...Expression) RowExpression {
|
||||
return jet.WRAP(Dialect, expressions...)
|
||||
}
|
||||
|
||||
// ROLLUP operator is used with the GROUP BY clause to generate all prefixes of a group of columns including the empty list.
|
||||
// It creates extra rows in the result set that represent the subtotal values for each combination of columns.
|
||||
var ROLLUP = jet.ROLLUP
|
||||
|
||||
// CUBE operator is used with the GROUP BY clause to generate subtotals for all possible combinations of a group of columns.
|
||||
// It creates extra rows in the result set that represent the subtotal values for each combination of columns.
|
||||
var CUBE = jet.CUBE
|
||||
|
||||
// GROUPING function is used to identify which columns are included in a grouping set or a subtotal row. It takes as input
|
||||
// the name of a column and returns 1 if the column is not included in the current grouping set, and 0 otherwise.
|
||||
// It can be also used with multiple parameters to check if a set of columns is included in the current grouping set. The result
|
||||
// of the GROUPING function would then be an integer bit mask having 1’s for the arguments which have GROUPING(argument) as 1.
|
||||
var GROUPING = jet.GROUPING
|
||||
|
||||
// range constructor functions
|
||||
var (
|
||||
// DATE_RANGE constructor function to create a date range
|
||||
DATE_RANGE = jet.DateRange
|
||||
// NUM_RANGE constructor function to create a numeric range
|
||||
NUM_RANGE = jet.NumRange
|
||||
// TS_RANGE constructor function to create a timestamp range
|
||||
TS_RANGE = jet.TsRange
|
||||
// TSTZ_RANGE constructor function to create a timestampz range
|
||||
TSTZ_RANGE = jet.TstzRange
|
||||
// INT4_RANGE constructor function to create a int4 range
|
||||
INT4_RANGE = jet.Int4Range
|
||||
// INT8_RANGE constructor function to create a int8 range
|
||||
INT8_RANGE = jet.Int8Range
|
||||
)
|
||||
36
tools/jet-2.12.0/postgres/functions_test.go
Normal file
36
tools/jet-2.12.0/postgres/functions_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestROW(t *testing.T) {
|
||||
assertSerialize(t, ROW(SELECT(Int(1))), `ROW((
|
||||
SELECT $1
|
||||
))`)
|
||||
assertSerialize(t, ROW(Int(1), SELECT(Int(2)), Float(11.11)), `ROW($1, (
|
||||
SELECT $2
|
||||
), $3)`)
|
||||
}
|
||||
|
||||
func TestDATE_TRUNC(t *testing.T) {
|
||||
assertSerialize(t, DATE_TRUNC(YEAR, NOW()), "DATE_TRUNC('YEAR', NOW())")
|
||||
assertSerialize(
|
||||
t,
|
||||
DATE_TRUNC(DAY, NOW().ADD(INTERVAL(1, HOUR)), "Australia/Sydney"),
|
||||
"DATE_TRUNC('DAY', NOW() + INTERVAL '1 HOUR', 'Australia/Sydney')",
|
||||
)
|
||||
}
|
||||
|
||||
func TestGENERATE_SERIES(t *testing.T) {
|
||||
assertSerialize(
|
||||
t,
|
||||
GENERATE_SERIES(NOW(), NOW().ADD(INTERVAL(10, DAY))),
|
||||
"GENERATE_SERIES(NOW(), NOW() + INTERVAL '10 DAY')",
|
||||
)
|
||||
assertSerialize(
|
||||
t,
|
||||
GENERATE_SERIES(NOW(), NOW().ADD(INTERVAL(10, DAY)), INTERVAL(2, DAY)),
|
||||
"GENERATE_SERIES(NOW(), NOW() + INTERVAL '10 DAY', INTERVAL '2 DAY')",
|
||||
)
|
||||
}
|
||||
77
tools/jet-2.12.0/postgres/insert_statement.go
Normal file
77
tools/jet-2.12.0/postgres/insert_statement.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// InsertStatement is interface for SQL INSERT statements
|
||||
type InsertStatement interface {
|
||||
jet.SerializerStatement
|
||||
|
||||
// Insert row of values
|
||||
VALUES(value interface{}, values ...interface{}) InsertStatement
|
||||
// Insert row of values, where value for each column is extracted from filed of structure data.
|
||||
// If data is not struct or there is no field for every column selected, this method will panic.
|
||||
MODEL(data interface{}) InsertStatement
|
||||
MODELS(data interface{}) InsertStatement
|
||||
QUERY(selectStatement SelectStatement) InsertStatement
|
||||
|
||||
ON_CONFLICT(indexExpressions ...jet.ColumnExpression) onConflict
|
||||
|
||||
RETURNING(projections ...Projection) InsertStatement
|
||||
}
|
||||
|
||||
func newInsertStatement(table WritableTable, columns []jet.Column) InsertStatement {
|
||||
newInsert := &insertStatementImpl{}
|
||||
newInsert.SerializerStatement = jet.NewStatementImpl(Dialect, jet.InsertStatementType, newInsert,
|
||||
&newInsert.Insert,
|
||||
&newInsert.ValuesQuery,
|
||||
&newInsert.OnConflict,
|
||||
&newInsert.Returning,
|
||||
)
|
||||
|
||||
newInsert.Insert.Table = table
|
||||
newInsert.Insert.Columns = columns
|
||||
|
||||
return newInsert
|
||||
}
|
||||
|
||||
type insertStatementImpl struct {
|
||||
jet.SerializerStatement
|
||||
|
||||
Insert jet.ClauseInsert
|
||||
ValuesQuery jet.ClauseValuesQuery
|
||||
Returning jet.ClauseReturning
|
||||
OnConflict onConflictClause
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement {
|
||||
i.ValuesQuery.Rows = append(i.ValuesQuery.Rows, jet.UnwindRowFromValues(value, values))
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) MODEL(data interface{}) InsertStatement {
|
||||
i.ValuesQuery.Rows = append(i.ValuesQuery.Rows, jet.UnwindRowFromModel(i.Insert.GetColumns(), data))
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) MODELS(data interface{}) InsertStatement {
|
||||
i.ValuesQuery.Rows = append(i.ValuesQuery.Rows, jet.UnwindRowsFromModels(i.Insert.GetColumns(), data)...)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) RETURNING(projections ...jet.Projection) InsertStatement {
|
||||
i.Returning.ProjectionList = projections
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) QUERY(selectStatement SelectStatement) InsertStatement {
|
||||
i.ValuesQuery.Query = selectStatement
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) ON_CONFLICT(indexExpressions ...jet.ColumnExpression) onConflict {
|
||||
i.OnConflict = onConflictClause{
|
||||
insertStatement: i,
|
||||
indexExpressions: indexExpressions,
|
||||
}
|
||||
return &i.OnConflict
|
||||
}
|
||||
201
tools/jet-2.12.0/postgres/insert_statement_test.go
Normal file
201
tools/jet-2.12.0/postgres/insert_statement_test.go
Normal file
@@ -0,0 +1,201 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInvalidInsert(t *testing.T) {
|
||||
assertStatementSqlErr(t, table1.INSERT(nil).VALUES(1), "jet: nil column in columns list")
|
||||
}
|
||||
|
||||
func TestInsertNilValue(t *testing.T) {
|
||||
assertStatementSql(t, table1.INSERT(table1Col1).VALUES(nil), `
|
||||
INSERT INTO db.table1 (col1)
|
||||
VALUES ($1);
|
||||
`, nil)
|
||||
}
|
||||
|
||||
func TestInsertSingleValue(t *testing.T) {
|
||||
assertStatementSql(t, table1.INSERT(table1Col1).VALUES(1), `
|
||||
INSERT INTO db.table1 (col1)
|
||||
VALUES ($1);
|
||||
`, int(1))
|
||||
}
|
||||
|
||||
func TestInsertWithColumnList(t *testing.T) {
|
||||
columnList := ColumnList{table3ColInt, table3StrCol}
|
||||
|
||||
assertStatementSql(t, table3.INSERT(columnList).VALUES(1, 3), `
|
||||
INSERT INTO db.table3 (col_int, col2)
|
||||
VALUES ($1, $2);
|
||||
`, 1, 3)
|
||||
}
|
||||
|
||||
func TestInsertDate(t *testing.T) {
|
||||
date := time.Date(1999, 1, 2, 3, 4, 5, 0, time.UTC)
|
||||
|
||||
assertStatementSql(t, table1.INSERT(table1ColTime).VALUES(date), `
|
||||
INSERT INTO db.table1 (col_time)
|
||||
VALUES ($1);
|
||||
`, date)
|
||||
}
|
||||
|
||||
func TestInsertMultipleValues(t *testing.T) {
|
||||
assertStatementSql(t, table1.INSERT(table1Col1, table1ColFloat, table1ColBool).VALUES(1, 2, 3), `
|
||||
INSERT INTO db.table1 (col1, col_float, col_bool)
|
||||
VALUES ($1, $2, $3);
|
||||
`, 1, 2, 3)
|
||||
}
|
||||
|
||||
func TestInsertMultipleRows(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
VALUES(1, 2).
|
||||
VALUES(11, 22).
|
||||
VALUES(111, 222)
|
||||
|
||||
assertStatementSql(t, stmt, `
|
||||
INSERT INTO db.table1 (col1, col_float)
|
||||
VALUES ($1, $2),
|
||||
($3, $4),
|
||||
($5, $6);
|
||||
`, 1, 2, 11, 22, 111, 222)
|
||||
}
|
||||
|
||||
func TestInsertValuesFromModel(t *testing.T) {
|
||||
type Table1Model struct {
|
||||
Col1 *int
|
||||
ColFloat float64
|
||||
}
|
||||
|
||||
one := 1
|
||||
|
||||
toInsert := Table1Model{
|
||||
Col1: &one,
|
||||
ColFloat: 1.11,
|
||||
}
|
||||
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
MODEL(toInsert).
|
||||
MODEL(&toInsert)
|
||||
|
||||
expectedSQL := `
|
||||
INSERT INTO db.table1 (col1, col_float)
|
||||
VALUES ($1, $2),
|
||||
($3, $4);
|
||||
`
|
||||
|
||||
assertStatementSql(t, stmt, expectedSQL, 1, float64(1.11), 1, float64(1.11))
|
||||
}
|
||||
|
||||
func TestInsertValuesFromModelColumnMismatch(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
require.Equal(t, r, "missing struct field for column : col1")
|
||||
}()
|
||||
type Table1Model struct {
|
||||
Col1Prim int
|
||||
Col2 string
|
||||
}
|
||||
|
||||
newData := Table1Model{
|
||||
Col1Prim: 1,
|
||||
Col2: "one",
|
||||
}
|
||||
|
||||
table1.
|
||||
INSERT(table1Col1, table1ColFloat).
|
||||
MODEL(newData)
|
||||
}
|
||||
|
||||
func TestInsertFromNonStructModel(t *testing.T) {
|
||||
|
||||
defer func() {
|
||||
r := recover()
|
||||
require.Equal(t, r, "jet: data has to be a struct")
|
||||
}()
|
||||
|
||||
table2.INSERT(table2ColInt).MODEL([]int{})
|
||||
}
|
||||
|
||||
func TestInsertQuery(t *testing.T) {
|
||||
|
||||
stmt := table1.INSERT(table1Col1).
|
||||
QUERY(table1.SELECT(table1Col1))
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO db.table1 (col1) (
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
);
|
||||
`
|
||||
assertStatementSql(t, stmt, expectedSQL)
|
||||
}
|
||||
|
||||
func TestInsertDefaultValue(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
VALUES(DEFAULT, "two")
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO db.table1 (col1, col_float)
|
||||
VALUES (DEFAULT, $1);
|
||||
`
|
||||
|
||||
assertStatementSql(t, stmt, expectedSQL, "two")
|
||||
}
|
||||
|
||||
func TestInsert_ON_CONFLICT(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColBool).
|
||||
VALUES("one", "two").
|
||||
VALUES("1", "2").
|
||||
VALUES("theta", "beta").
|
||||
ON_CONFLICT(table1ColBool).WHERE(table1ColBool.IS_NOT_FALSE()).
|
||||
DO_UPDATE(
|
||||
SET(table1ColBool.SET(Bool(true)),
|
||||
table2ColInt.SET(Int(1)),
|
||||
ColumnList{table1Col1, table1ColBool}.SET(ROW(Int(2), String("two"))),
|
||||
).WHERE(table1Col1.GT(Int(2))),
|
||||
).
|
||||
RETURNING(table1Col1, table1ColBool)
|
||||
|
||||
assertDebugStatementSql(t, stmt, `
|
||||
INSERT INTO db.table1 (col1, col_bool)
|
||||
VALUES ('one', 'two'),
|
||||
('1', '2'),
|
||||
('theta', 'beta')
|
||||
ON CONFLICT (col_bool) WHERE col_bool IS NOT FALSE DO UPDATE
|
||||
SET col_bool = TRUE::boolean,
|
||||
col_int = 1,
|
||||
(col1, col_bool) = ROW(2, 'two'::text)
|
||||
WHERE table1.col1 > 2
|
||||
RETURNING table1.col1 AS "table1.col1",
|
||||
table1.col_bool AS "table1.col_bool";
|
||||
`)
|
||||
}
|
||||
|
||||
func TestInsert_ON_CONFLICT_ON_CONSTRAINT(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColBool).
|
||||
VALUES("one", "two").
|
||||
VALUES("1", "2").
|
||||
ON_CONFLICT().ON_CONSTRAINT("idk_primary_key").
|
||||
DO_UPDATE(
|
||||
SET(table1ColBool.SET(Bool(false)),
|
||||
table2ColInt.SET(Int(1)),
|
||||
ColumnList{table1Col1, table1ColBool}.SET(ROW(Int(2), String("two"))),
|
||||
).WHERE(table1Col1.GT(Int(2)))).
|
||||
RETURNING(table1Col1, table1ColBool)
|
||||
|
||||
assertDebugStatementSql(t, stmt, `
|
||||
INSERT INTO db.table1 (col1, col_bool)
|
||||
VALUES ('one', 'two'),
|
||||
('1', '2')
|
||||
ON CONFLICT ON CONSTRAINT idk_primary_key DO UPDATE
|
||||
SET col_bool = FALSE::boolean,
|
||||
col_int = 1,
|
||||
(col1, col_bool) = ROW(2, 'two'::text)
|
||||
WHERE table1.col1 > 2
|
||||
RETURNING table1.col1 AS "table1.col1",
|
||||
table1.col_bool AS "table1.col_bool";
|
||||
`)
|
||||
}
|
||||
257
tools/jet-2.12.0/postgres/interval_expression.go
Normal file
257
tools/jet-2.12.0/postgres/interval_expression.go
Normal file
@@ -0,0 +1,257 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
"github.com/go-jet/jet/v2/internal/utils/datetime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type quantityAndUnit = float64
|
||||
type unit = float64
|
||||
|
||||
// Interval unit types
|
||||
const (
|
||||
YEAR unit = 123456789 + iota
|
||||
MONTH
|
||||
WEEK
|
||||
DAY
|
||||
HOUR
|
||||
MINUTE
|
||||
SECOND
|
||||
MILLISECOND
|
||||
MICROSECOND
|
||||
DECADE
|
||||
CENTURY
|
||||
MILLENNIUM
|
||||
)
|
||||
|
||||
// IntervalExpression is representation of postgres INTERVAL
|
||||
type IntervalExpression interface {
|
||||
jet.IsInterval
|
||||
jet.Expression
|
||||
|
||||
EQ(rhs IntervalExpression) BoolExpression
|
||||
NOT_EQ(rhs IntervalExpression) BoolExpression
|
||||
IS_DISTINCT_FROM(rhs IntervalExpression) BoolExpression
|
||||
IS_NOT_DISTINCT_FROM(rhs IntervalExpression) BoolExpression
|
||||
|
||||
LT(rhs IntervalExpression) BoolExpression
|
||||
LT_EQ(rhs IntervalExpression) BoolExpression
|
||||
GT(rhs IntervalExpression) BoolExpression
|
||||
GT_EQ(rhs IntervalExpression) BoolExpression
|
||||
BETWEEN(min, max IntervalExpression) BoolExpression
|
||||
NOT_BETWEEN(min, max IntervalExpression) BoolExpression
|
||||
|
||||
ADD(rhs IntervalExpression) IntervalExpression
|
||||
SUB(rhs IntervalExpression) IntervalExpression
|
||||
|
||||
MUL(rhs NumericExpression) IntervalExpression
|
||||
DIV(rhs NumericExpression) IntervalExpression
|
||||
}
|
||||
|
||||
type intervalInterfaceImpl struct {
|
||||
jet.IsIntervalImpl
|
||||
|
||||
parent IntervalExpression
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) EQ(rhs IntervalExpression) BoolExpression {
|
||||
return jet.Eq(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) NOT_EQ(rhs IntervalExpression) BoolExpression {
|
||||
return jet.NotEq(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) IS_DISTINCT_FROM(rhs IntervalExpression) BoolExpression {
|
||||
return jet.IsDistinctFrom(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs IntervalExpression) BoolExpression {
|
||||
return jet.IsNotDistinctFrom(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) LT(rhs IntervalExpression) BoolExpression {
|
||||
return jet.Lt(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) LT_EQ(rhs IntervalExpression) BoolExpression {
|
||||
return jet.LtEq(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) GT(rhs IntervalExpression) BoolExpression {
|
||||
return jet.Gt(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) GT_EQ(rhs IntervalExpression) BoolExpression {
|
||||
return jet.GtEq(i.parent, rhs)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) BETWEEN(min, max IntervalExpression) BoolExpression {
|
||||
return jet.NewBetweenOperatorExpression(i.parent, min, max, false)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) NOT_BETWEEN(min, max IntervalExpression) BoolExpression {
|
||||
return jet.NewBetweenOperatorExpression(i.parent, min, max, true)
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) ADD(rhs IntervalExpression) IntervalExpression {
|
||||
return IntervalExp(jet.Add(i.parent, rhs))
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) SUB(rhs IntervalExpression) IntervalExpression {
|
||||
return IntervalExp(jet.Sub(i.parent, rhs))
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) MUL(rhs NumericExpression) IntervalExpression {
|
||||
return IntervalExp(jet.Mul(i.parent, rhs))
|
||||
}
|
||||
|
||||
func (i *intervalInterfaceImpl) DIV(rhs NumericExpression) IntervalExpression {
|
||||
return IntervalExp(jet.Div(i.parent, rhs))
|
||||
}
|
||||
|
||||
type intervalExpression struct {
|
||||
jet.Expression
|
||||
intervalInterfaceImpl
|
||||
}
|
||||
|
||||
// INTERVAL creates new interval expression from the list of quantity-unit pairs.
|
||||
//
|
||||
// INTERVAL(1, DAY, 3, MINUTE)
|
||||
func INTERVAL(quantityAndUnit ...quantityAndUnit) IntervalExpression {
|
||||
quantityAndUnitLen := len(quantityAndUnit)
|
||||
if quantityAndUnitLen == 0 || quantityAndUnitLen%2 != 0 {
|
||||
panic("jet: invalid number of quantity and unit fields")
|
||||
}
|
||||
|
||||
var fields []string
|
||||
|
||||
for i := 0; i < len(quantityAndUnit); i += 2 {
|
||||
quantity := strconv.FormatFloat(quantityAndUnit[i], 'f', -1, 64)
|
||||
unitString := unitToString(quantityAndUnit[i+1])
|
||||
fields = append(fields, quantity+" "+unitString)
|
||||
}
|
||||
|
||||
intervalStr := fmt.Sprintf("INTERVAL '%s'", strings.Join(fields, " "))
|
||||
|
||||
newInterval := &intervalExpression{}
|
||||
|
||||
newInterval.Expression = jet.RawWithParent(intervalStr, newInterval)
|
||||
newInterval.intervalInterfaceImpl.parent = newInterval
|
||||
|
||||
return newInterval
|
||||
}
|
||||
|
||||
// INTERVALd creates interval expression from time.Duration
|
||||
func INTERVALd(duration time.Duration) IntervalExpression {
|
||||
days, hours, minutes, seconds, microseconds := datetime.ExtractTimeComponents(duration)
|
||||
|
||||
var quantityAndUnits []quantityAndUnit
|
||||
|
||||
if days > 0 {
|
||||
quantityAndUnits = append(quantityAndUnits, quantityAndUnit(days))
|
||||
quantityAndUnits = append(quantityAndUnits, DAY)
|
||||
}
|
||||
|
||||
if hours > 0 {
|
||||
quantityAndUnits = append(quantityAndUnits, quantityAndUnit(hours))
|
||||
quantityAndUnits = append(quantityAndUnits, HOUR)
|
||||
}
|
||||
|
||||
if minutes > 0 {
|
||||
quantityAndUnits = append(quantityAndUnits, quantityAndUnit(minutes))
|
||||
quantityAndUnits = append(quantityAndUnits, MINUTE)
|
||||
}
|
||||
|
||||
if seconds > 0 {
|
||||
quantityAndUnits = append(quantityAndUnits, quantityAndUnit(seconds))
|
||||
quantityAndUnits = append(quantityAndUnits, SECOND)
|
||||
}
|
||||
|
||||
if microseconds > 0 {
|
||||
quantityAndUnits = append(quantityAndUnits, quantityAndUnit(microseconds))
|
||||
quantityAndUnits = append(quantityAndUnits, MICROSECOND)
|
||||
}
|
||||
|
||||
if len(quantityAndUnits) == 0 {
|
||||
return INTERVAL(0, MICROSECOND)
|
||||
}
|
||||
|
||||
return INTERVAL(quantityAndUnits...)
|
||||
}
|
||||
|
||||
func unitToString(unit quantityAndUnit) string {
|
||||
switch unit {
|
||||
case YEAR:
|
||||
return "YEAR"
|
||||
case MONTH:
|
||||
return "MONTH"
|
||||
case WEEK:
|
||||
return "WEEK"
|
||||
case DAY:
|
||||
return "DAY"
|
||||
case HOUR:
|
||||
return "HOUR"
|
||||
case MINUTE:
|
||||
return "MINUTE"
|
||||
case SECOND:
|
||||
return "SECOND"
|
||||
case MILLISECOND:
|
||||
return "MILLISECOND"
|
||||
case MICROSECOND:
|
||||
return "MICROSECOND"
|
||||
case DECADE:
|
||||
return "DECADE"
|
||||
case CENTURY:
|
||||
return "CENTURY"
|
||||
case MILLENNIUM:
|
||||
return "MILLENNIUM"
|
||||
// additional field units for EXTRACT function
|
||||
case DOW:
|
||||
return "DOW"
|
||||
case DOY:
|
||||
return "DOY"
|
||||
case EPOCH:
|
||||
return "EPOCH"
|
||||
case ISODOW:
|
||||
return "ISODOW"
|
||||
case ISOYEAR:
|
||||
return "ISOYEAR"
|
||||
case JULIAN:
|
||||
return "JULIAN"
|
||||
case QUARTER:
|
||||
return "QUARTER"
|
||||
case TIMEZONE:
|
||||
return "TIMEZONE"
|
||||
case TIMEZONE_HOUR:
|
||||
return "TIMEZONE_HOUR"
|
||||
case TIMEZONE_MINUTE:
|
||||
return "TIMEZONE_MINUTE"
|
||||
default:
|
||||
panic("jet: invalid INTERVAL unit type")
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------//
|
||||
|
||||
type intervalWrapper struct {
|
||||
intervalInterfaceImpl
|
||||
Expression
|
||||
}
|
||||
|
||||
func newIntervalExpressionWrap(expression Expression) IntervalExpression {
|
||||
intervalWrap := &intervalWrapper{Expression: expression}
|
||||
intervalWrap.intervalInterfaceImpl.parent = intervalWrap
|
||||
return intervalWrap
|
||||
}
|
||||
|
||||
// IntervalExp is interval expression wrapper around arbitrary expression.
|
||||
// Allows go compiler to see any expression as interval expression.
|
||||
// Does not add sql cast to generated sql builder output.
|
||||
func IntervalExp(expression Expression) IntervalExpression {
|
||||
return newIntervalExpressionWrap(expression)
|
||||
}
|
||||
84
tools/jet-2.12.0/postgres/interval_expression_test.go
Normal file
84
tools/jet-2.12.0/postgres/interval_expression_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestINTERVAL(t *testing.T) {
|
||||
assertSerialize(t, INTERVAL(1, YEAR), "INTERVAL '1 YEAR'")
|
||||
assertSerialize(t, INTERVAL(1, MONTH), "INTERVAL '1 MONTH'")
|
||||
assertSerialize(t, INTERVAL(1, WEEK), "INTERVAL '1 WEEK'")
|
||||
assertSerialize(t, INTERVAL(1, DAY), "INTERVAL '1 DAY'")
|
||||
assertSerialize(t, INTERVAL(1, HOUR), "INTERVAL '1 HOUR'")
|
||||
assertSerialize(t, INTERVAL(1, MINUTE), "INTERVAL '1 MINUTE'")
|
||||
assertSerialize(t, INTERVAL(1, SECOND), "INTERVAL '1 SECOND'")
|
||||
assertSerialize(t, INTERVAL(1, MILLISECOND), "INTERVAL '1 MILLISECOND'")
|
||||
assertSerialize(t, INTERVAL(1, MICROSECOND), "INTERVAL '1 MICROSECOND'")
|
||||
assertSerialize(t, INTERVAL(1, DECADE), "INTERVAL '1 DECADE'")
|
||||
assertSerialize(t, INTERVAL(1, CENTURY), "INTERVAL '1 CENTURY'")
|
||||
assertSerialize(t, INTERVAL(1, MILLENNIUM), "INTERVAL '1 MILLENNIUM'")
|
||||
|
||||
assertSerialize(t, INTERVAL(1, YEAR, 10, MONTH), "INTERVAL '1 YEAR 10 MONTH'")
|
||||
assertSerialize(t, INTERVAL(1, YEAR, 10, MONTH, 20, DAY), "INTERVAL '1 YEAR 10 MONTH 20 DAY'")
|
||||
assertSerialize(t, INTERVAL(1, YEAR, 10, MONTH, 20, DAY, 3, HOUR), "INTERVAL '1 YEAR 10 MONTH 20 DAY 3 HOUR'")
|
||||
|
||||
assertSerialize(t, INTERVAL(1, YEAR).IS_NOT_NULL(), "INTERVAL '1 YEAR' IS NOT NULL")
|
||||
assertProjectionSerialize(t, INTERVAL(1, YEAR).AS("one year"), `INTERVAL '1 YEAR' AS "one year"`)
|
||||
|
||||
f := 5.2
|
||||
assertSerialize(t, INTERVAL(f, YEAR), "INTERVAL '5.2 YEAR'")
|
||||
}
|
||||
|
||||
func TestINTERVALd(t *testing.T) {
|
||||
assertSerialize(t, INTERVALd(0), "INTERVAL '0 MICROSECOND'")
|
||||
assertSerialize(t, INTERVALd(1*time.Microsecond), "INTERVAL '1 MICROSECOND'")
|
||||
assertSerialize(t, INTERVALd(1*time.Millisecond), "INTERVAL '1000 MICROSECOND'")
|
||||
assertSerialize(t, INTERVALd(1*time.Second), "INTERVAL '1 SECOND'")
|
||||
assertSerialize(t, INTERVALd(1*time.Minute), "INTERVAL '1 MINUTE'")
|
||||
assertSerialize(t, INTERVALd(1*time.Hour), "INTERVAL '1 HOUR'")
|
||||
assertSerialize(t, INTERVALd(24*time.Hour), "INTERVAL '1 DAY'")
|
||||
|
||||
assertSerialize(t, INTERVALd(24*time.Hour+2*time.Hour+3*time.Minute+4*time.Second+5*time.Microsecond),
|
||||
"INTERVAL '1 DAY 2 HOUR 3 MINUTE 4 SECOND 5 MICROSECOND'")
|
||||
}
|
||||
|
||||
func TestINTERVAL_InvalidParams(t *testing.T) {
|
||||
assertPanicErr(t, func() { INTERVAL() }, "jet: invalid number of quantity and unit fields")
|
||||
assertPanicErr(t, func() { INTERVAL(1) }, "jet: invalid number of quantity and unit fields")
|
||||
assertPanicErr(t, func() { INTERVAL(1, 2) }, "jet: invalid INTERVAL unit type")
|
||||
}
|
||||
|
||||
func TestDateTimeIntervalArithmetic(t *testing.T) {
|
||||
assertSerialize(t, table2ColDate.ADD(INTERVAL(1, HOUR)), "(table2.col_date + INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColDate.SUB(INTERVAL(1, HOUR)), "(table2.col_date - INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTime.ADD(INTERVAL(1, HOUR)), "(table2.col_time + INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTime.SUB(INTERVAL(1, HOUR)), "(table2.col_time - INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTimez.ADD(INTERVAL(1, HOUR)), "(table2.col_timez + INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTimez.SUB(INTERVAL(1, HOUR)), "(table2.col_timez - INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTimestamp.ADD(INTERVAL(1, HOUR)), "(table2.col_timestamp + INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTimestamp.SUB(INTERVAL(1, HOUR)), "(table2.col_timestamp - INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTimestampz.ADD(INTERVAL(1, HOUR)), "(table2.col_timestampz + INTERVAL '1 HOUR')")
|
||||
assertSerialize(t, table2ColTimestampz.SUB(INTERVAL(1, HOUR)), "(table2.col_timestampz - INTERVAL '1 HOUR')")
|
||||
}
|
||||
|
||||
func TestIntervalExpressionMethods(t *testing.T) {
|
||||
assertSerialize(t, table1ColInterval.EQ(table2ColInterval), "(table1.col_interval = table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.EQ(INTERVAL(10, SECOND)), "(table1.col_interval = INTERVAL '10 SECOND')")
|
||||
assertSerialize(t, table1ColInterval.EQ(INTERVALd(11*time.Minute)), "(table1.col_interval = INTERVAL '11 MINUTE')")
|
||||
assertSerialize(t, table1ColInterval.EQ(INTERVALd(11*time.Minute)).EQ(Bool(false)),
|
||||
"((table1.col_interval = INTERVAL '11 MINUTE') = $1::boolean)", false)
|
||||
assertSerialize(t, table1ColInterval.NOT_EQ(table2ColInterval), "(table1.col_interval != table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.IS_DISTINCT_FROM(table2ColInterval), "(table1.col_interval IS DISTINCT FROM table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.IS_NOT_DISTINCT_FROM(table2ColInterval), "(table1.col_interval IS NOT DISTINCT FROM table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.LT(table2ColInterval), "(table1.col_interval < table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.LT_EQ(table2ColInterval), "(table1.col_interval <= table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.GT(table2ColInterval), "(table1.col_interval > table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.GT_EQ(table2ColInterval), "(table1.col_interval >= table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.ADD(table2ColInterval), "(table1.col_interval + table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.SUB(table2ColInterval), "(table1.col_interval - table2.col_interval)")
|
||||
assertSerialize(t, table1ColInterval.MUL(table2ColInt), "(table1.col_interval * table2.col_int)")
|
||||
assertSerialize(t, table1ColInterval.MUL(table2ColFloat), "(table1.col_interval * table2.col_float)")
|
||||
assertSerialize(t, table1ColInterval.DIV(table2ColInt), "(table1.col_interval / table2.col_int)")
|
||||
assertSerialize(t, table1ColInterval.DIV(table2ColFloat), "(table1.col_interval / table2.col_float)")
|
||||
}
|
||||
19
tools/jet-2.12.0/postgres/keywords.go
Normal file
19
tools/jet-2.12.0/postgres/keywords.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
const (
|
||||
// DEFAULT is jet equivalent of SQL DEFAULT
|
||||
DEFAULT = jet.DEFAULT
|
||||
)
|
||||
|
||||
var (
|
||||
// NULL is jet equivalent of SQL NULL
|
||||
NULL = jet.NULL
|
||||
// STAR is jet equivalent of SQL *
|
||||
STAR = jet.STAR
|
||||
// PLUS_INFINITY is jet equivalent for sql infinity
|
||||
PLUS_INFINITY = jet.PLUS_INFINITY
|
||||
// MINUS_INFINITY is jet equivalent for sql -infinity
|
||||
MINUS_INFINITY = jet.MINUS_INFINITY
|
||||
)
|
||||
24
tools/jet-2.12.0/postgres/lateral.go
Normal file
24
tools/jet-2.12.0/postgres/lateral.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// LATERAL derived tables constructor from select statement
|
||||
func LATERAL(selectStmt SelectStatement) lateralImpl {
|
||||
return lateralImpl{
|
||||
selectStmt: selectStmt,
|
||||
}
|
||||
}
|
||||
|
||||
type lateralImpl struct {
|
||||
selectStmt SelectStatement
|
||||
}
|
||||
|
||||
func (l lateralImpl) AS(alias string) SelectTable {
|
||||
subQuery := &selectTableImpl{
|
||||
SelectTable: jet.NewLateral(l.selectStmt, alias),
|
||||
}
|
||||
|
||||
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||
|
||||
return subQuery
|
||||
}
|
||||
14
tools/jet-2.12.0/postgres/lateral_test.go
Normal file
14
tools/jet-2.12.0/postgres/lateral_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package postgres
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLATERAL(t *testing.T) {
|
||||
assertSerialize(t,
|
||||
LATERAL(
|
||||
SELECT(Int(1)),
|
||||
).AS("lat1"),
|
||||
|
||||
`LATERAL (
|
||||
SELECT $1
|
||||
) AS lat1`)
|
||||
}
|
||||
182
tools/jet-2.12.0/postgres/literal.go
Normal file
182
tools/jet-2.12.0/postgres/literal.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
// Bool is boolean literal constructor
|
||||
func Bool(value bool) BoolExpression {
|
||||
return CAST(jet.Bool(value)).AS_BOOL()
|
||||
}
|
||||
|
||||
// Int is constructor for 64 bit signed integer expressions literals.
|
||||
var Int = jet.Int
|
||||
|
||||
// Int8 is constructor for 8 bit signed integer expressions literals.
|
||||
func Int8(value int8) IntegerExpression {
|
||||
return CAST(jet.Int8(value)).AS_SMALLINT()
|
||||
}
|
||||
|
||||
// Int16 is constructor for 16 bit signed integer expressions literals.
|
||||
func Int16(value int16) IntegerExpression {
|
||||
return CAST(jet.Int16(value)).AS_SMALLINT()
|
||||
}
|
||||
|
||||
// Int32 is constructor for 32 bit signed integer expressions literals.
|
||||
func Int32(value int32) IntegerExpression {
|
||||
return CAST(jet.Int32(value)).AS_INTEGER()
|
||||
}
|
||||
|
||||
// Int64 is constructor for 64 bit signed integer expressions literals.
|
||||
func Int64(value int64) IntegerExpression {
|
||||
return CAST(jet.Int(value)).AS_BIGINT()
|
||||
}
|
||||
|
||||
// Uint8 is constructor for 8 bit unsigned integer expressions literals.
|
||||
func Uint8(value uint8) IntegerExpression {
|
||||
return CAST(jet.Uint8(value)).AS_SMALLINT()
|
||||
}
|
||||
|
||||
// Uint16 is constructor for 16 bit unsigned integer expressions literals.
|
||||
func Uint16(value uint16) IntegerExpression {
|
||||
return CAST(jet.Uint16(value)).AS_INTEGER()
|
||||
}
|
||||
|
||||
// Uint32 is constructor for 32 bit unsigned integer expressions literals.
|
||||
func Uint32(value uint32) IntegerExpression {
|
||||
return CAST(jet.Uint32(value)).AS_BIGINT()
|
||||
}
|
||||
|
||||
// Float creates new float literal expression
|
||||
var Float = jet.Float
|
||||
|
||||
// Real is placeholder constructor for 32-bit float literals
|
||||
func Real(value float32) FloatExpression {
|
||||
return CAST(jet.Literal(value)).AS_REAL()
|
||||
}
|
||||
|
||||
// Double is placeholder constructor for 64-bit float literals
|
||||
func Double(value float64) FloatExpression {
|
||||
return CAST(jet.Literal(value)).AS_DOUBLE()
|
||||
}
|
||||
|
||||
// Decimal creates new float literal expression
|
||||
var Decimal = jet.Decimal
|
||||
|
||||
// String is a parameter constructor for the PostgreSQL text type. Using the `Text` constructor is
|
||||
// generally preferable.
|
||||
//
|
||||
// WARNING: String always applies a `text` type cast, which can be problematic if a parameter is compared
|
||||
// to a `character` column, as this may prevent index usage. In such cases, consider using the Char
|
||||
// constructor instead. See also other PostgreSQL-specific constructors: Text, Char, and VarChar.
|
||||
func String(value string) StringExpression {
|
||||
return CAST(jet.String(value)).AS_TEXT()
|
||||
}
|
||||
|
||||
// Text is a parameter constructor for the PostgreSQL text type. This constructor also adds an
|
||||
// explicit placeholder type cast to text in the generated query, such as `$3::text`.
|
||||
// Example usage:
|
||||
//
|
||||
// Text("English")
|
||||
func Text(value string) StringExpression {
|
||||
return CAST(jet.Literal(value)).AS_TEXT()
|
||||
}
|
||||
|
||||
// Char is a parameter constructor for the PostgreSQL character type. This constructor also adds an
|
||||
// explicit placeholder type cast to text in the generated query, such as `$3::char(30)`.
|
||||
// Example usage:
|
||||
//
|
||||
// Char(20)("English")
|
||||
func Char(length ...int) func(value string) StringExpression {
|
||||
return func(value string) StringExpression {
|
||||
return CAST(StringExp(jet.Literal(value))).AS_CHAR(length...)
|
||||
}
|
||||
}
|
||||
|
||||
// VarChar is a parameter constructor for the PostgreSQL character varying type. This constructor
|
||||
// also adds an explicit placeholder type cast to text in the generated query, such as `$3::varchar(30)`.
|
||||
// Example usage:
|
||||
//
|
||||
// VarChar(20)("English")
|
||||
// VarChar()("English")
|
||||
func VarChar(length ...int) func(value string) StringExpression {
|
||||
return func(value string) StringExpression {
|
||||
return CAST(StringExp(jet.Literal(value))).AS_VARCHAR(length...)
|
||||
}
|
||||
}
|
||||
|
||||
// Json creates new json literal expression
|
||||
func Json(value interface{}) StringExpression {
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
default:
|
||||
panic("Bytea parameter value has to be of the type string or []byte")
|
||||
}
|
||||
return StringExp(CAST(jet.Literal(value)).AS("json"))
|
||||
}
|
||||
|
||||
// UUID is a helper function to create string literal expression from uuid object
|
||||
// value can be any uuid type with a String method
|
||||
var UUID = jet.UUID
|
||||
|
||||
// Bytea creates new bytea literal expression
|
||||
func Bytea(value interface{}) StringExpression {
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
default:
|
||||
panic("Bytea parameter value has to be of the type string or []byte")
|
||||
}
|
||||
return CAST(jet.Literal(value)).AS_BYTEA()
|
||||
}
|
||||
|
||||
// Date creates new date literal expression
|
||||
func Date(year int, month time.Month, day int) DateExpression {
|
||||
return CAST(jet.Date(year, month, day)).AS_DATE()
|
||||
}
|
||||
|
||||
// DateT creates new date literal expression from time.Time object
|
||||
func DateT(t time.Time) DateExpression {
|
||||
return CAST(jet.DateT(t)).AS_DATE()
|
||||
}
|
||||
|
||||
// Time creates new time literal expression
|
||||
func Time(hour, minute, second int, nanoseconds ...time.Duration) TimeExpression {
|
||||
return CAST(jet.Time(hour, minute, second, nanoseconds...)).AS_TIME()
|
||||
}
|
||||
|
||||
// TimeT creates new time literal expression from time.Time object
|
||||
func TimeT(t time.Time) TimeExpression {
|
||||
return CAST(jet.TimeT(t)).AS_TIME()
|
||||
}
|
||||
|
||||
// Timez creates new time with time zone literal expression
|
||||
func Timez(hour, minute, second int, milliseconds time.Duration, timezone string) TimezExpression {
|
||||
return CAST(jet.Timez(hour, minute, second, milliseconds, timezone)).AS_TIMEZ()
|
||||
}
|
||||
|
||||
// TimezT creates new time with time zone literal expression from time.Time object
|
||||
func TimezT(t time.Time) TimezExpression {
|
||||
return CAST(jet.TimezT(t)).AS_TIMEZ()
|
||||
}
|
||||
|
||||
// Timestamp creates new timestamp literal expression
|
||||
func Timestamp(year int, month time.Month, day, hour, minute, second int, milliseconds ...time.Duration) TimestampExpression {
|
||||
return CAST(jet.Timestamp(year, month, day, hour, minute, second, milliseconds...)).AS_TIMESTAMP()
|
||||
}
|
||||
|
||||
// TimestampT creates new timestamp literal expression from time.Time object
|
||||
func TimestampT(t time.Time) TimestampExpression {
|
||||
return CAST(jet.TimestampT(t)).AS_TIMESTAMP()
|
||||
}
|
||||
|
||||
// Timestampz creates new timestamp with time zone literal expression
|
||||
func Timestampz(year int, month time.Month, day, hour, minute, second int, milliseconds time.Duration, timezone string) TimestampzExpression {
|
||||
return CAST(jet.Timestampz(year, month, day, hour, minute, second, milliseconds, timezone)).AS_TIMESTAMPZ()
|
||||
}
|
||||
|
||||
// TimestampzT creates new timestamp literal expression from time.Time object
|
||||
func TimestampzT(t time.Time) TimestampzExpression {
|
||||
return CAST(jet.TimestampzT(t)).AS_TIMESTAMPZ()
|
||||
}
|
||||
105
tools/jet-2.12.0/postgres/literal_test.go
Normal file
105
tools/jet-2.12.0/postgres/literal_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBool(t *testing.T) {
|
||||
assertSerialize(t, Bool(false), `$1::boolean`, false)
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
assertSerialize(t, Int(11), `$1`, int64(11))
|
||||
}
|
||||
|
||||
func TestInt8(t *testing.T) {
|
||||
val := int8(math.MinInt8)
|
||||
assertSerialize(t, Int8(val), `$1::smallint`, val)
|
||||
}
|
||||
|
||||
func TestInt16(t *testing.T) {
|
||||
val := int16(math.MinInt16)
|
||||
assertSerialize(t, Int16(val), `$1::smallint`, val)
|
||||
}
|
||||
|
||||
func TestInt32(t *testing.T) {
|
||||
val := int32(math.MinInt32)
|
||||
assertSerialize(t, Int32(val), `$1::integer`, val)
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
val := int64(math.MinInt64)
|
||||
assertSerialize(t, Int64(val), `$1::bigint`, val)
|
||||
}
|
||||
|
||||
func TestUint8(t *testing.T) {
|
||||
val := uint8(math.MaxUint8)
|
||||
assertSerialize(t, Uint8(val), `$1::smallint`, val)
|
||||
}
|
||||
|
||||
func TestUint16(t *testing.T) {
|
||||
val := uint16(math.MaxUint16)
|
||||
assertSerialize(t, Uint16(val), `$1::integer`, val)
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
val := uint32(math.MaxUint32)
|
||||
assertSerialize(t, Uint32(val), `$1::bigint`, val)
|
||||
}
|
||||
|
||||
func TestFloat(t *testing.T) {
|
||||
assertSerialize(t, Float(12.34), `$1`, float64(12.34))
|
||||
|
||||
assertSerialize(t, Real(12.34), `$1::real`, float32(12.34))
|
||||
assertSerialize(t, Double(12.34), `$1::double precision`, float64(12.34))
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
assertSerialize(t, String("Some text"), `$1::text`, "Some text")
|
||||
|
||||
assertSerialize(t, Text("Some text"), `$1::text`, "Some text")
|
||||
assertSerialize(t, Char(20)("John Doe"), `$1::char(20)`, "John Doe")
|
||||
assertSerialize(t, Char()("John Doe"), `$1::char`, "John Doe")
|
||||
assertSerialize(t, VarChar(20)("John Doe"), `$1::varchar(20)`, "John Doe")
|
||||
assertSerialize(t, VarChar()("John Doe"), `$1::varchar`, "John Doe")
|
||||
}
|
||||
|
||||
func TestBytea(t *testing.T) {
|
||||
assertSerialize(t, Bytea("Some text"), `$1::bytea`, "Some text")
|
||||
assertSerialize(t, Bytea([]byte("Some byte array")), `$1::bytea`, []byte("Some byte array"))
|
||||
}
|
||||
|
||||
func TestJson(t *testing.T) {
|
||||
assertSerialize(t, Json("{\"key\": \"value\"}"), `$1::json`, "{\"key\": \"value\"}")
|
||||
assertSerialize(t, Json([]byte("{\"key\": \"value\"}")), `$1::json`, []byte("{\"key\": \"value\"}"))
|
||||
}
|
||||
|
||||
func TestDate(t *testing.T) {
|
||||
assertSerialize(t, Date(2014, time.January, 2), `$1::date`, "2014-01-02")
|
||||
assertSerialize(t, DateT(time.Now()), `$1::date`)
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
assertSerialize(t, Time(10, 15, 30), `$1::time without time zone`, "10:15:30")
|
||||
assertSerialize(t, TimeT(time.Now()), `$1::time without time zone`)
|
||||
}
|
||||
|
||||
func TestTimez(t *testing.T) {
|
||||
assertSerialize(t, Timez(10, 15, 30, 0, "UTC"),
|
||||
`$1::time with time zone`, "10:15:30 UTC")
|
||||
assertSerialize(t, TimezT(time.Now()), `$1::time with time zone`)
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
assertSerialize(t, Timestamp(2010, time.March, 30, 10, 15, 30),
|
||||
`$1::timestamp without time zone`, "2010-03-30 10:15:30")
|
||||
assertSerialize(t, TimestampT(time.Now()), `$1::timestamp without time zone`)
|
||||
}
|
||||
|
||||
func TestTimestampz(t *testing.T) {
|
||||
assertSerialize(t, Timestampz(2010, time.March, 30, 10, 15, 30, 0, "UTC"),
|
||||
`$1::timestamp with time zone`, "2010-03-30 10:15:30 UTC")
|
||||
assertSerialize(t, TimestampzT(time.Now()), `$1::timestamp with time zone`)
|
||||
}
|
||||
56
tools/jet-2.12.0/postgres/lock_statement.go
Normal file
56
tools/jet-2.12.0/postgres/lock_statement.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// TableLockMode is a type of possible SQL table lock
|
||||
type TableLockMode string
|
||||
|
||||
// Lock types for LockStatement.
|
||||
const (
|
||||
LOCK_ACCESS_SHARE TableLockMode = "ACCESS SHARE"
|
||||
LOCK_ROW_SHARE TableLockMode = "ROW SHARE"
|
||||
LOCK_ROW_EXCLUSIVE TableLockMode = "ROW EXCLUSIVE"
|
||||
LOCK_SHARE_UPDATE_EXCLUSIVE TableLockMode = "SHARE UPDATE EXCLUSIVE"
|
||||
LOCK_SHARE TableLockMode = "SHARE"
|
||||
LOCK_SHARE_ROW_EXCLUSIVE TableLockMode = "SHARE ROW EXCLUSIVE"
|
||||
LOCK_EXCLUSIVE TableLockMode = "EXCLUSIVE"
|
||||
LOCK_ACCESS_EXCLUSIVE TableLockMode = "ACCESS EXCLUSIVE"
|
||||
)
|
||||
|
||||
// LockStatement is interface for MySQL LOCK tables
|
||||
type LockStatement interface {
|
||||
Statement
|
||||
|
||||
IN(lockMode TableLockMode) LockStatement
|
||||
NOWAIT() LockStatement
|
||||
}
|
||||
|
||||
// LOCK creates LockStatement from list of tables
|
||||
func LOCK(tables ...jet.SerializerTable) LockStatement {
|
||||
newLock := &lockStatementImpl{}
|
||||
newLock.SerializerStatement = jet.NewStatementImpl(Dialect, jet.LockStatementType, newLock,
|
||||
&newLock.StatementBegin, &newLock.In, &newLock.NoWait)
|
||||
|
||||
newLock.StatementBegin.Name = "LOCK TABLE"
|
||||
newLock.StatementBegin.Tables = tables
|
||||
newLock.NoWait.Name = "NOWAIT"
|
||||
return newLock
|
||||
}
|
||||
|
||||
type lockStatementImpl struct {
|
||||
jet.SerializerStatement
|
||||
|
||||
StatementBegin jet.ClauseStatementBegin
|
||||
In jet.ClauseIn
|
||||
NoWait jet.ClauseOptional
|
||||
}
|
||||
|
||||
func (l *lockStatementImpl) IN(lockMode TableLockMode) LockStatement {
|
||||
l.In.LockMode = string(lockMode)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *lockStatementImpl) NOWAIT() LockStatement {
|
||||
l.NoWait.Show = true
|
||||
return l
|
||||
}
|
||||
32
tools/jet-2.12.0/postgres/lock_statement_test.go
Normal file
32
tools/jet-2.12.0/postgres/lock_statement_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLockTable(t *testing.T) {
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_ACCESS_SHARE), `
|
||||
LOCK TABLE db.table1 IN ACCESS SHARE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_ROW_SHARE), `
|
||||
LOCK TABLE db.table1 IN ROW SHARE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_ROW_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN ROW EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_SHARE_UPDATE_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN SHARE UPDATE EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_SHARE), `
|
||||
LOCK TABLE db.table1 IN SHARE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_SHARE_ROW_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN SHARE ROW EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatementSql(t, table1.LOCK().IN(LOCK_ACCESS_EXCLUSIVE).NOWAIT(), `
|
||||
LOCK TABLE db.table1 IN ACCESS EXCLUSIVE MODE NOWAIT;
|
||||
`)
|
||||
}
|
||||
12
tools/jet-2.12.0/postgres/operators.go
Normal file
12
tools/jet-2.12.0/postgres/operators.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// NOT returns negation of bool expression result
|
||||
var NOT = jet.NOT
|
||||
|
||||
// BIT_NOT inverts every bit in integer expression result
|
||||
var BIT_NOT = jet.BIT_NOT
|
||||
|
||||
// DISTINCT operator can be used to return distinct values of expr
|
||||
var DISTINCT = jet.DISTINCT
|
||||
231
tools/jet-2.12.0/postgres/select_statement.go
Normal file
231
tools/jet-2.12.0/postgres/select_statement.go
Normal file
@@ -0,0 +1,231 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
// RowLock is interface for SELECT statement row lock types
|
||||
type RowLock = jet.RowLock
|
||||
|
||||
// Row lock types
|
||||
var (
|
||||
UPDATE = jet.NewRowLock("UPDATE")
|
||||
NO_KEY_UPDATE = jet.NewRowLock("NO KEY UPDATE")
|
||||
SHARE = jet.NewRowLock("SHARE")
|
||||
KEY_SHARE = jet.NewRowLock("KEY SHARE")
|
||||
)
|
||||
|
||||
// Window function clauses
|
||||
var (
|
||||
PARTITION_BY = jet.PARTITION_BY
|
||||
ORDER_BY = jet.ORDER_BY
|
||||
UNBOUNDED = int64(math.MaxInt64)
|
||||
CURRENT_ROW = jet.CURRENT_ROW
|
||||
)
|
||||
|
||||
// PRECEDING window frame clause
|
||||
func PRECEDING(offset int64) jet.FrameExtent {
|
||||
return jet.PRECEDING(toJetFrameOffset(offset))
|
||||
}
|
||||
|
||||
// FOLLOWING window frame clause
|
||||
func FOLLOWING(offset int64) jet.FrameExtent {
|
||||
return jet.FOLLOWING(toJetFrameOffset(offset))
|
||||
}
|
||||
|
||||
// Window definition reference
|
||||
var Window = jet.WindowName
|
||||
|
||||
// SelectStatement is interface for PostgreSQL SELECT statement
|
||||
type SelectStatement interface {
|
||||
Statement
|
||||
jet.HasProjections
|
||||
Expression
|
||||
|
||||
DISTINCT(on ...jet.ColumnExpression) SelectStatement
|
||||
FROM(tables ...ReadableTable) SelectStatement
|
||||
WHERE(expression BoolExpression) SelectStatement
|
||||
GROUP_BY(groupByClauses ...GroupByClause) SelectStatement
|
||||
HAVING(boolExpression BoolExpression) SelectStatement
|
||||
WINDOW(name string) windowExpand
|
||||
ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
|
||||
LIMIT(limit int64) SelectStatement
|
||||
OFFSET(offset int64) SelectStatement
|
||||
// OFFSET_e can be used when an integer expression is needed as offset, otherwise OFFSET can be used
|
||||
OFFSET_e(offset IntegerExpression) SelectStatement
|
||||
FETCH_FIRST(count IntegerExpression) fetchExpand
|
||||
FOR(lock RowLock) SelectStatement
|
||||
|
||||
UNION(rhs SelectStatement) setStatement
|
||||
UNION_ALL(rhs SelectStatement) setStatement
|
||||
INTERSECT(rhs SelectStatement) setStatement
|
||||
INTERSECT_ALL(rhs SelectStatement) setStatement
|
||||
EXCEPT(rhs SelectStatement) setStatement
|
||||
EXCEPT_ALL(rhs SelectStatement) setStatement
|
||||
|
||||
AsTable(alias string) SelectTable
|
||||
}
|
||||
|
||||
// SELECT creates new SelectStatement with list of projections
|
||||
func SELECT(projection Projection, projections ...Projection) SelectStatement {
|
||||
return newSelectStatement(nil, append([]Projection{projection}, projections...))
|
||||
}
|
||||
|
||||
func newSelectStatement(table ReadableTable, projections []Projection) SelectStatement {
|
||||
newSelect := &selectStatementImpl{}
|
||||
newSelect.ExpressionStatement = jet.NewExpressionStatementImpl(Dialect, jet.SelectStatementType, newSelect,
|
||||
&newSelect.Select,
|
||||
&newSelect.From,
|
||||
&newSelect.Where,
|
||||
&newSelect.GroupBy,
|
||||
&newSelect.Having,
|
||||
&newSelect.Window,
|
||||
&newSelect.OrderBy,
|
||||
&newSelect.Limit,
|
||||
&newSelect.Offset,
|
||||
&newSelect.Fetch,
|
||||
&newSelect.For)
|
||||
|
||||
newSelect.Select.ProjectionList = projections
|
||||
if table != nil {
|
||||
newSelect.From.Tables = []jet.Serializer{table}
|
||||
}
|
||||
newSelect.Limit.Count = -1
|
||||
|
||||
newSelect.setOperatorsImpl.parent = newSelect
|
||||
|
||||
return newSelect
|
||||
}
|
||||
|
||||
type selectStatementImpl struct {
|
||||
jet.ExpressionStatement
|
||||
setOperatorsImpl
|
||||
|
||||
Select jet.ClauseSelect
|
||||
From jet.ClauseFrom
|
||||
Where jet.ClauseWhere
|
||||
GroupBy jet.ClauseGroupBy
|
||||
Having jet.ClauseHaving
|
||||
Window jet.ClauseWindow
|
||||
OrderBy jet.ClauseOrderBy
|
||||
Limit jet.ClauseLimit
|
||||
Offset jet.ClauseOffset
|
||||
Fetch jet.ClauseFetch
|
||||
For jet.ClauseFor
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) DISTINCT(on ...jet.ColumnExpression) SelectStatement {
|
||||
s.Select.Distinct = true
|
||||
s.Select.DistinctOnColumns = on
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
|
||||
s.From.Tables = readableTablesToSerializerList(tables)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) WHERE(condition BoolExpression) SelectStatement {
|
||||
s.Where.Condition = condition
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) GROUP_BY(groupByClauses ...GroupByClause) SelectStatement {
|
||||
s.GroupBy.List = groupByClauses
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) HAVING(boolExpression BoolExpression) SelectStatement {
|
||||
s.Having.Condition = boolExpression
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) WINDOW(name string) windowExpand {
|
||||
s.Window.Definitions = append(s.Window.Definitions, jet.WindowDefinition{Name: name})
|
||||
return windowExpand{selectStatement: s}
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) SelectStatement {
|
||||
s.OrderBy.List = orderByClauses
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) LIMIT(limit int64) SelectStatement {
|
||||
s.Limit.Count = limit
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) OFFSET(offset int64) SelectStatement {
|
||||
s.Offset.Count = Int(offset)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) OFFSET_e(offset IntegerExpression) SelectStatement {
|
||||
s.Offset.Count = offset
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) FETCH_FIRST(count IntegerExpression) fetchExpand {
|
||||
s.Fetch.Count = count
|
||||
|
||||
return fetchExpand{
|
||||
selectStatement: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) FOR(lock RowLock) SelectStatement {
|
||||
s.For.Lock = lock
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s, alias, nil)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
|
||||
type windowExpand struct {
|
||||
selectStatement *selectStatementImpl
|
||||
}
|
||||
|
||||
func (w windowExpand) AS(window ...jet.Window) SelectStatement {
|
||||
if len(window) == 0 {
|
||||
return w.selectStatement
|
||||
}
|
||||
windowsDefinition := w.selectStatement.Window.Definitions
|
||||
windowsDefinition[len(windowsDefinition)-1].Window = window[0]
|
||||
return w.selectStatement
|
||||
}
|
||||
|
||||
func toJetFrameOffset(offset int64) jet.Serializer {
|
||||
if offset == UNBOUNDED {
|
||||
return jet.UNBOUNDED
|
||||
}
|
||||
return jet.FixedLiteral(offset)
|
||||
}
|
||||
|
||||
func readableTablesToSerializerList(tables []ReadableTable) []jet.Serializer {
|
||||
var ret []jet.Serializer
|
||||
for _, table := range tables {
|
||||
ret = append(ret, table)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type fetchExpand struct {
|
||||
selectStatement *selectStatementImpl
|
||||
}
|
||||
|
||||
func (f fetchExpand) ROWS_ONLY() SelectStatement {
|
||||
f.selectStatement.Fetch.WithTies = false
|
||||
|
||||
return f.selectStatement
|
||||
}
|
||||
|
||||
func (f fetchExpand) ROWS_WITH_TIES() SelectStatement {
|
||||
f.selectStatement.Fetch.WithTies = true
|
||||
|
||||
return f.selectStatement
|
||||
}
|
||||
142
tools/jet-2.12.0/postgres/select_statement_test.go
Normal file
142
tools/jet-2.12.0/postgres/select_statement_test.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInvalidSelect(t *testing.T) {
|
||||
assertStatementSqlErr(t, SELECT(nil), "jet: Projection is nil")
|
||||
}
|
||||
|
||||
func TestSelectColumnList(t *testing.T) {
|
||||
columnList := ColumnList{table2ColInt, table2ColFloat, table3ColInt}
|
||||
|
||||
assertStatementSql(t, SELECT(columnList).FROM(table2), `
|
||||
SELECT table2.col_int AS "table2.col_int",
|
||||
table2.col_float AS "table2.col_float",
|
||||
table3.col_int AS "table3.col_int"
|
||||
FROM db.table2;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectLiterals(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(Int(1), Float(2.2), Bool(false)).FROM(table1), `
|
||||
SELECT $1,
|
||||
$2,
|
||||
$3::boolean
|
||||
FROM db.table1;
|
||||
`, int64(1), 2.2, false)
|
||||
}
|
||||
|
||||
func TestSelectDistinct(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table1ColBool).DISTINCT().FROM(table1), `
|
||||
SELECT DISTINCT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectFrom(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table1ColInt, table2ColFloat).FROM(table1), `
|
||||
SELECT table1.col_int AS "table1.col_int",
|
||||
table2.col_float AS "table2.col_float"
|
||||
FROM db.table1;
|
||||
`)
|
||||
assertStatementSql(t, SELECT(table1ColInt, table2ColFloat).FROM(table1.INNER_JOIN(table2, table1ColInt.EQ(table2ColInt))), `
|
||||
SELECT table1.col_int AS "table1.col_int",
|
||||
table2.col_float AS "table2.col_float"
|
||||
FROM db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.col_int);
|
||||
`)
|
||||
assertStatementSql(t, table1.INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)).SELECT(table1ColInt, table2ColFloat), `
|
||||
SELECT table1.col_int AS "table1.col_int",
|
||||
table2.col_float AS "table2.col_float"
|
||||
FROM db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.col_int);
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectWhere(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table1ColInt).FROM(table1).WHERE(Bool(true)), `
|
||||
SELECT table1.col_int AS "table1.col_int"
|
||||
FROM db.table1
|
||||
WHERE $1::boolean;
|
||||
`, true)
|
||||
assertStatementSql(t, SELECT(table1ColInt).FROM(table1).WHERE(table1ColInt.GT_EQ(Int(10))), `
|
||||
SELECT table1.col_int AS "table1.col_int"
|
||||
FROM db.table1
|
||||
WHERE table1.col_int >= $1;
|
||||
`, int64(10))
|
||||
}
|
||||
|
||||
func TestSelectGroupBy(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table2ColInt).FROM(table2).GROUP_BY(table2ColFloat), `
|
||||
SELECT table2.col_int AS "table2.col_int"
|
||||
FROM db.table2
|
||||
GROUP BY table2.col_float;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectHaving(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table3ColInt).FROM(table3).HAVING(table1ColBool.EQ(Bool(true))), `
|
||||
SELECT table3.col_int AS "table3.col_int"
|
||||
FROM db.table3
|
||||
HAVING table1.col_bool = $1::boolean;
|
||||
`, true)
|
||||
}
|
||||
|
||||
func TestSelectOrderBy(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table2ColFloat).FROM(table2).ORDER_BY(table2ColInt.DESC()), `
|
||||
SELECT table2.col_float AS "table2.col_float"
|
||||
FROM db.table2
|
||||
ORDER BY table2.col_int DESC;
|
||||
`)
|
||||
assertStatementSql(t, SELECT(table2ColFloat).FROM(table2).ORDER_BY(table2ColInt.DESC(), table2ColInt.ASC()), `
|
||||
SELECT table2.col_float AS "table2.col_float"
|
||||
FROM db.table2
|
||||
ORDER BY table2.col_int DESC, table2.col_int ASC;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectLimitOffset(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table2ColInt).FROM(table2).LIMIT(10), `
|
||||
SELECT table2.col_int AS "table2.col_int"
|
||||
FROM db.table2
|
||||
LIMIT $1;
|
||||
`, int64(10))
|
||||
assertStatementSql(t, SELECT(table2ColInt).FROM(table2).LIMIT(10).OFFSET(2), `
|
||||
SELECT table2.col_int AS "table2.col_int"
|
||||
FROM db.table2
|
||||
LIMIT $1
|
||||
OFFSET $2;
|
||||
`, int64(10), int64(2))
|
||||
}
|
||||
|
||||
func TestSelectLock(t *testing.T) {
|
||||
assertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR UPDATE;
|
||||
`)
|
||||
assertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(SHARE().NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR SHARE NOWAIT;
|
||||
`)
|
||||
|
||||
assertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(KEY_SHARE().NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR KEY SHARE NOWAIT;
|
||||
`)
|
||||
assertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(NO_KEY_UPDATE().SKIP_LOCKED()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR NO KEY UPDATE SKIP LOCKED;
|
||||
`)
|
||||
|
||||
assertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE().OF(table1, table2).NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR UPDATE OF table1, table2 NOWAIT;
|
||||
`)
|
||||
}
|
||||
24
tools/jet-2.12.0/postgres/select_table.go
Normal file
24
tools/jet-2.12.0/postgres/select_table.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// SelectTable is interface for postgres temporary tables like sub-queries, VALUES, CTEs etc...
|
||||
type SelectTable interface {
|
||||
readableTable
|
||||
jet.SelectTable
|
||||
}
|
||||
|
||||
type selectTableImpl struct {
|
||||
jet.SelectTable
|
||||
readableTableInterfaceImpl
|
||||
}
|
||||
|
||||
func newSelectTable(serializerWithProjections jet.SerializerHasProjections, alias string, columnAliases []jet.ColumnExpression) SelectTable {
|
||||
subQuery := &selectTableImpl{
|
||||
SelectTable: jet.NewSelectTable(serializerWithProjections, alias, columnAliases),
|
||||
}
|
||||
|
||||
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||
|
||||
return subQuery
|
||||
}
|
||||
150
tools/jet-2.12.0/postgres/set_statement.go
Normal file
150
tools/jet-2.12.0/postgres/set_statement.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// UNION effectively appends the result of sub-queries(select statements) into single query.
|
||||
// It eliminates duplicate rows from its result.
|
||||
func UNION(lhs, rhs jet.SerializerStatement, selects ...jet.SerializerStatement) setStatement {
|
||||
return newSetStatementImpl(union, false, toSelectList(lhs, rhs, selects...))
|
||||
}
|
||||
|
||||
// UNION_ALL effectively appends the result of sub-queries(select statements) into single query.
|
||||
// It does not eliminates duplicate rows from its result.
|
||||
func UNION_ALL(lhs, rhs jet.SerializerStatement, selects ...jet.SerializerStatement) setStatement {
|
||||
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 jet.SerializerStatement, selects ...jet.SerializerStatement) setStatement {
|
||||
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 jet.SerializerStatement, selects ...jet.SerializerStatement) setStatement {
|
||||
return newSetStatementImpl(intersect, true, 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 jet.SerializerStatement) setStatement {
|
||||
return newSetStatementImpl(except, false, toSelectList(lhs, rhs))
|
||||
}
|
||||
|
||||
// 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 jet.SerializerStatement) setStatement {
|
||||
return newSetStatementImpl(except, true, toSelectList(lhs, rhs))
|
||||
}
|
||||
|
||||
type setStatement interface {
|
||||
setOperators
|
||||
|
||||
ORDER_BY(orderByClauses ...OrderByClause) setStatement
|
||||
|
||||
LIMIT(limit int64) setStatement
|
||||
OFFSET(offset int64) setStatement
|
||||
// OFFSET_e can be used when an integer expression is needed as offset, otherwise OFFSET can be used
|
||||
OFFSET_e(offset IntegerExpression) setStatement
|
||||
|
||||
AsTable(alias string) SelectTable
|
||||
}
|
||||
|
||||
type setOperators interface {
|
||||
Statement
|
||||
jet.HasProjections
|
||||
Expression
|
||||
|
||||
UNION(rhs SelectStatement) setStatement
|
||||
UNION_ALL(rhs SelectStatement) setStatement
|
||||
INTERSECT(rhs SelectStatement) setStatement
|
||||
INTERSECT_ALL(rhs SelectStatement) setStatement
|
||||
EXCEPT(rhs SelectStatement) setStatement
|
||||
EXCEPT_ALL(rhs SelectStatement) setStatement
|
||||
}
|
||||
|
||||
type setOperatorsImpl struct {
|
||||
parent setOperators
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) UNION(rhs SelectStatement) setStatement {
|
||||
return UNION(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) UNION_ALL(rhs SelectStatement) setStatement {
|
||||
return UNION_ALL(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) INTERSECT(rhs SelectStatement) setStatement {
|
||||
return INTERSECT(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) INTERSECT_ALL(rhs SelectStatement) setStatement {
|
||||
return INTERSECT_ALL(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) EXCEPT(rhs SelectStatement) setStatement {
|
||||
return EXCEPT(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) EXCEPT_ALL(rhs SelectStatement) setStatement {
|
||||
return EXCEPT_ALL(s.parent, rhs)
|
||||
}
|
||||
|
||||
type setStatementImpl struct {
|
||||
jet.ExpressionStatement
|
||||
|
||||
setOperatorsImpl
|
||||
|
||||
setOperator jet.ClauseSetStmtOperator
|
||||
}
|
||||
|
||||
func newSetStatementImpl(operator string, all bool, selects []jet.SerializerStatement) setStatement {
|
||||
newSetStatement := &setStatementImpl{}
|
||||
newSetStatement.ExpressionStatement = jet.NewExpressionStatementImpl(Dialect, jet.SetStatementType, newSetStatement,
|
||||
&newSetStatement.setOperator)
|
||||
|
||||
newSetStatement.setOperator.Operator = operator
|
||||
newSetStatement.setOperator.All = all
|
||||
newSetStatement.setOperator.Selects = selects
|
||||
newSetStatement.setOperator.Limit.Count = -1
|
||||
|
||||
newSetStatement.setOperatorsImpl.parent = newSetStatement
|
||||
|
||||
return newSetStatement
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) setStatement {
|
||||
s.setOperator.OrderBy.List = orderByClauses
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) LIMIT(limit int64) setStatement {
|
||||
s.setOperator.Limit.Count = limit
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) OFFSET(offset int64) setStatement {
|
||||
s.setOperator.Offset.Count = Int(offset)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) OFFSET_e(offset IntegerExpression) setStatement {
|
||||
s.setOperator.Offset.Count = offset
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s, alias, nil)
|
||||
}
|
||||
|
||||
const (
|
||||
union = "UNION"
|
||||
intersect = "INTERSECT"
|
||||
except = "EXCEPT"
|
||||
)
|
||||
|
||||
func toSelectList(lhs, rhs jet.SerializerStatement, selects ...jet.SerializerStatement) []jet.SerializerStatement {
|
||||
return append([]jet.SerializerStatement{lhs, rhs}, selects...)
|
||||
}
|
||||
81
tools/jet-2.12.0/postgres/set_statement_test.go
Normal file
81
tools/jet-2.12.0/postgres/set_statement_test.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSelectSets(t *testing.T) {
|
||||
select1 := SELECT(table1ColBool).FROM(table1)
|
||||
select2 := SELECT(table2ColBool).FROM(table2)
|
||||
|
||||
assertStatementSql(t, select1.UNION(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
UNION
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
assertStatementSql(t, select1.UNION_ALL(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
UNION ALL
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
assertStatementSql(t, select1.INTERSECT(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
INTERSECT
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
assertStatementSql(t, select1.INTERSECT_ALL(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
INTERSECT ALL
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
assertStatementSql(t, select1.EXCEPT(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
EXCEPT
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
assertStatementSql(t, select1.EXCEPT_ALL(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
EXCEPT ALL
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
}
|
||||
10
tools/jet-2.12.0/postgres/statement.go
Normal file
10
tools/jet-2.12.0/postgres/statement.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
// RawStatement creates new sql statements from raw query and optional map of named arguments
|
||||
func RawStatement(rawQuery string, namedArguments ...RawArgs) jet.SerializerStatement {
|
||||
return jet.RawStatement(Dialect, rawQuery, namedArguments...)
|
||||
}
|
||||
137
tools/jet-2.12.0/postgres/table.go
Normal file
137
tools/jet-2.12.0/postgres/table.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// Table is interface for MySQL tables
|
||||
type Table interface {
|
||||
readableTable
|
||||
writableTable
|
||||
jet.SerializerTable
|
||||
}
|
||||
|
||||
type readableTable interface {
|
||||
// Generates a select query on the current tableName.
|
||||
SELECT(projection Projection, projections ...Projection) SelectStatement
|
||||
|
||||
// Creates a inner join tableName Expression using onCondition.
|
||||
INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a left join tableName Expression using onCondition.
|
||||
LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a right join tableName Expression using onCondition.
|
||||
RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a full join tableName Expression using onCondition.
|
||||
FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a cross join tableName Expression using onCondition.
|
||||
CROSS_JOIN(table ReadableTable) ReadableTable
|
||||
}
|
||||
|
||||
type writableTable interface {
|
||||
INSERT(columns ...jet.Column) InsertStatement
|
||||
UPDATE(columns ...jet.Column) UpdateStatement
|
||||
DELETE() DeleteStatement
|
||||
LOCK() LockStatement
|
||||
}
|
||||
|
||||
// ReadableTable interface
|
||||
type ReadableTable interface {
|
||||
readableTable
|
||||
jet.Serializer
|
||||
}
|
||||
|
||||
// WritableTable interface
|
||||
type WritableTable interface {
|
||||
jet.Table
|
||||
writableTable
|
||||
jet.Serializer
|
||||
}
|
||||
|
||||
type readableTableInterfaceImpl struct {
|
||||
parent ReadableTable
|
||||
}
|
||||
|
||||
// Generates a select query on the current tableName.
|
||||
func (r readableTableInterfaceImpl) SELECT(projection1 Projection, projections ...Projection) SelectStatement {
|
||||
return newSelectStatement(r.parent, append([]Projection{projection1}, projections...))
|
||||
}
|
||||
|
||||
// Creates a inner join tableName Expression using onCondition.
|
||||
func (r readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.InnerJoin, onCondition)
|
||||
}
|
||||
|
||||
// Creates a left join tableName Expression using onCondition.
|
||||
func (r readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.LeftJoin, onCondition)
|
||||
}
|
||||
|
||||
// Creates a right join tableName Expression using onCondition.
|
||||
func (r readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.RightJoin, onCondition)
|
||||
}
|
||||
|
||||
func (r readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.FullJoin, onCondition)
|
||||
}
|
||||
|
||||
func (r readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.CrossJoin, nil)
|
||||
}
|
||||
|
||||
type writableTableInterfaceImpl struct {
|
||||
parent WritableTable
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) INSERT(columns ...jet.Column) InsertStatement {
|
||||
return newInsertStatement(w.parent, jet.UnwidColumnList(columns))
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) UPDATE(columns ...jet.Column) UpdateStatement {
|
||||
return newUpdateStatement(w.parent, jet.UnwidColumnList(columns))
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) DELETE() DeleteStatement {
|
||||
return newDeleteStatement(w.parent)
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) LOCK() LockStatement {
|
||||
return LOCK(w.parent)
|
||||
}
|
||||
|
||||
type tableImpl struct {
|
||||
readableTableInterfaceImpl
|
||||
writableTableInterfaceImpl
|
||||
|
||||
jet.SerializerTable
|
||||
}
|
||||
|
||||
// NewTable creates new table with schema Name, table Name and list of columns
|
||||
func NewTable(schemaName, name, alias string, columns ...jet.ColumnExpression) Table {
|
||||
|
||||
t := &tableImpl{
|
||||
SerializerTable: jet.NewTable(schemaName, name, alias, columns...),
|
||||
}
|
||||
|
||||
t.readableTableInterfaceImpl.parent = t
|
||||
t.writableTableInterfaceImpl.parent = t
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
type joinTable struct {
|
||||
readableTableInterfaceImpl
|
||||
jet.JoinTable
|
||||
}
|
||||
|
||||
func newJoinTable(lhs jet.Serializer, rhs jet.Serializer, joinType jet.JoinType, onCondition BoolExpression) ReadableTable {
|
||||
newJoinTable := &joinTable{
|
||||
JoinTable: jet.NewJoinTable(lhs, rhs, joinType, onCondition),
|
||||
}
|
||||
|
||||
newJoinTable.readableTableInterfaceImpl.parent = newJoinTable
|
||||
|
||||
return newJoinTable
|
||||
}
|
||||
124
tools/jet-2.12.0/postgres/table_test.go
Normal file
124
tools/jet-2.12.0/postgres/table_test.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJoinNilInputs(t *testing.T) {
|
||||
assertSerializeErr(t, table2.INNER_JOIN(nil, table1ColBool.EQ(table2ColBool)),
|
||||
"jet: right hand side of join operation is nil table")
|
||||
assertSerializeErr(t, table2.INNER_JOIN(table1, nil),
|
||||
"jet: join condition is nil")
|
||||
}
|
||||
|
||||
func TestINNER_JOIN(t *testing.T) {
|
||||
assertSerialize(t, table1.
|
||||
INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)).
|
||||
INNER_JOIN(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.col_int)
|
||||
INNER JOIN db.table3 ON (table1.col_int = table3.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
INNER_JOIN(table2, table1ColInt.EQ(Int(1))).
|
||||
INNER_JOIN(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = $1)
|
||||
INNER JOIN db.table3 ON (table1.col_int = $2)`, int64(1), int64(2))
|
||||
}
|
||||
|
||||
func TestLEFT_JOIN(t *testing.T) {
|
||||
assertSerialize(t, table1.
|
||||
LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
LEFT JOIN db.table2 ON (table1.col_int = table2.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)).
|
||||
LEFT_JOIN(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
LEFT JOIN db.table2 ON (table1.col_int = table2.col_int)
|
||||
LEFT JOIN db.table3 ON (table1.col_int = table3.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
LEFT_JOIN(table2, table1ColInt.EQ(Int(1))).
|
||||
LEFT_JOIN(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
LEFT JOIN db.table2 ON (table1.col_int = $1)
|
||||
LEFT JOIN db.table3 ON (table1.col_int = $2)`, int64(1), int64(2))
|
||||
}
|
||||
|
||||
func TestRIGHT_JOIN(t *testing.T) {
|
||||
assertSerialize(t, table1.
|
||||
RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
RIGHT JOIN db.table2 ON (table1.col_int = table2.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)).
|
||||
RIGHT_JOIN(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
RIGHT JOIN db.table2 ON (table1.col_int = table2.col_int)
|
||||
RIGHT JOIN db.table3 ON (table1.col_int = table3.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
RIGHT_JOIN(table2, table1ColInt.EQ(Int(1))).
|
||||
RIGHT_JOIN(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
RIGHT JOIN db.table2 ON (table1.col_int = $1)
|
||||
RIGHT JOIN db.table3 ON (table1.col_int = $2)`, int64(1), int64(2))
|
||||
}
|
||||
|
||||
func TestFULL_JOIN(t *testing.T) {
|
||||
assertSerialize(t, table1.
|
||||
FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
FULL JOIN db.table2 ON (table1.col_int = table2.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)).
|
||||
FULL_JOIN(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
FULL JOIN db.table2 ON (table1.col_int = table2.col_int)
|
||||
FULL JOIN db.table3 ON (table1.col_int = table3.col_int)`)
|
||||
assertSerialize(t, table1.
|
||||
FULL_JOIN(table2, table1ColInt.EQ(Int(1))).
|
||||
FULL_JOIN(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
FULL JOIN db.table2 ON (table1.col_int = $1)
|
||||
FULL JOIN db.table3 ON (table1.col_int = $2)`, int64(1), int64(2))
|
||||
}
|
||||
|
||||
func TestCROSS_JOIN(t *testing.T) {
|
||||
assertSerialize(t, table1.
|
||||
CROSS_JOIN(table2),
|
||||
`db.table1
|
||||
CROSS JOIN db.table2`)
|
||||
assertSerialize(t, table1.
|
||||
CROSS_JOIN(table2).
|
||||
CROSS_JOIN(table3),
|
||||
`db.table1
|
||||
CROSS JOIN db.table2
|
||||
CROSS JOIN db.table3`)
|
||||
}
|
||||
|
||||
func TestImplicitCROSS_JOIN(t *testing.T) {
|
||||
assertDebugStatementSql(t,
|
||||
SELECT(table1Col1, table2Col3).
|
||||
FROM(table1, table2),
|
||||
`
|
||||
SELECT table1.col1 AS "table1.col1",
|
||||
table2.col3 AS "table2.col3"
|
||||
FROM db.table1,
|
||||
db.table2;
|
||||
`)
|
||||
assertDebugStatementSql(t,
|
||||
SELECT(
|
||||
table1Col1, table2Col3,
|
||||
).FROM(table1, table2, table3),
|
||||
`
|
||||
SELECT table1.col1 AS "table1.col1",
|
||||
table2.col3 AS "table2.col3"
|
||||
FROM db.table1,
|
||||
db.table2,
|
||||
db.table3;
|
||||
`)
|
||||
}
|
||||
37
tools/jet-2.12.0/postgres/types.go
Normal file
37
tools/jet-2.12.0/postgres/types.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// Statement is common interface for all statements(SELECT, INSERT, UPDATE, DELETE, LOCK)
|
||||
type Statement = jet.Statement
|
||||
|
||||
// Rows wraps sql.Rows type with a support for query result mapping
|
||||
type Rows = jet.Rows
|
||||
|
||||
// Projection is interface for all projection types. Types that can be part of, for instance SELECT clause.
|
||||
type Projection = jet.Projection
|
||||
|
||||
// ProjectionList can be used to create conditional constructed projection list.
|
||||
type ProjectionList = jet.ProjectionList
|
||||
|
||||
// ColumnAssigment is interface wrapper around column assigment
|
||||
type ColumnAssigment = jet.ColumnAssigment
|
||||
|
||||
// PrintableStatement is a statement which sql query can be logged
|
||||
type PrintableStatement = jet.PrintableStatement
|
||||
|
||||
// OrderByClause is the combination of an expression and the wanted ordering to use as input for ORDER BY.
|
||||
type OrderByClause = jet.OrderByClause
|
||||
|
||||
// GroupByClause interface to use as input for GROUP_BY
|
||||
type GroupByClause = jet.GroupByClause
|
||||
|
||||
// SetLogger sets automatic statement logging function
|
||||
// Deprecated: use SetQueryLogger instead.
|
||||
var SetLogger = jet.SetLoggerFunc
|
||||
|
||||
// SetQueryLogger sets automatic query logging function.
|
||||
var SetQueryLogger = jet.SetQueryLogger
|
||||
|
||||
// QueryInfo contains information about executed query
|
||||
type QueryInfo = jet.QueryInfo
|
||||
119
tools/jet-2.12.0/postgres/update_statement.go
Normal file
119
tools/jet-2.12.0/postgres/update_statement.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
)
|
||||
|
||||
// UpdateStatement is interface of SQL UPDATE statement
|
||||
type UpdateStatement interface {
|
||||
jet.SerializerStatement
|
||||
|
||||
SET(value interface{}, values ...interface{}) UpdateStatement
|
||||
MODEL(data interface{}) UpdateStatement
|
||||
|
||||
FROM(tables ...ReadableTable) UpdateStatement
|
||||
WHERE(expression BoolExpression) UpdateStatement
|
||||
RETURNING(projections ...Projection) UpdateStatement
|
||||
}
|
||||
|
||||
type updateStatementImpl struct {
|
||||
jet.SerializerStatement
|
||||
|
||||
Update jet.ClauseUpdate
|
||||
Set clauseSet
|
||||
SetNew jet.SetClauseNew
|
||||
From jet.ClauseFrom
|
||||
Where jet.ClauseWhere
|
||||
Returning jet.ClauseReturning
|
||||
}
|
||||
|
||||
func newUpdateStatement(table WritableTable, columns []jet.Column) UpdateStatement {
|
||||
update := &updateStatementImpl{}
|
||||
update.SerializerStatement = jet.NewStatementImpl(Dialect, jet.UpdateStatementType, update,
|
||||
&update.Update,
|
||||
&update.Set,
|
||||
&update.SetNew,
|
||||
&update.From,
|
||||
&update.Where,
|
||||
&update.Returning)
|
||||
|
||||
update.Update.Table = table
|
||||
update.Set.Columns = columns
|
||||
update.Where.Mandatory = true
|
||||
|
||||
return update
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement {
|
||||
columnAssigment, isColumnAssigment := value.(ColumnAssigment)
|
||||
|
||||
if isColumnAssigment {
|
||||
u.SetNew = []ColumnAssigment{columnAssigment}
|
||||
for _, value := range values {
|
||||
u.SetNew = append(u.SetNew, value.(ColumnAssigment))
|
||||
}
|
||||
} else {
|
||||
u.Set.Values = jet.UnwindRowFromValues(value, values)
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement {
|
||||
u.Set.Values = jet.UnwindRowFromModel(u.Set.Columns, data)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) FROM(tables ...ReadableTable) UpdateStatement {
|
||||
u.From.Tables = readableTablesToSerializerList(tables)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) WHERE(expression BoolExpression) UpdateStatement {
|
||||
u.Where.Condition = expression
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) RETURNING(projections ...jet.Projection) UpdateStatement {
|
||||
u.Returning.ProjectionList = projections
|
||||
return u
|
||||
}
|
||||
|
||||
type clauseSet struct {
|
||||
Columns []jet.Column
|
||||
Values []jet.Serializer
|
||||
}
|
||||
|
||||
func (s *clauseSet) Serialize(statementType jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
|
||||
if len(s.Values) == 0 {
|
||||
return
|
||||
}
|
||||
out.NewLine()
|
||||
out.WriteString("SET")
|
||||
|
||||
if len(s.Columns) == 0 {
|
||||
panic("jet: no columns selected")
|
||||
}
|
||||
|
||||
if len(s.Columns) > 1 {
|
||||
out.WriteString("(")
|
||||
}
|
||||
|
||||
jet.SerializeColumnNames(s.Columns, out)
|
||||
|
||||
if len(s.Columns) > 1 {
|
||||
out.WriteString(")")
|
||||
}
|
||||
|
||||
out.WriteString("=")
|
||||
|
||||
if len(s.Values) > 1 {
|
||||
out.WriteString("(")
|
||||
}
|
||||
|
||||
jet.SerializeClauseList(statementType, s.Values, out)
|
||||
|
||||
if len(s.Values) > 1 {
|
||||
out.WriteString(")")
|
||||
}
|
||||
}
|
||||
62
tools/jet-2.12.0/postgres/update_statement_test.go
Normal file
62
tools/jet-2.12.0/postgres/update_statement_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUpdateWithOneValue(t *testing.T) {
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET col_int = $1
|
||||
WHERE table1.col_int >= $2;
|
||||
`
|
||||
stmt := table1.UPDATE(table1ColInt).
|
||||
SET(1).
|
||||
WHERE(table1ColInt.GT_EQ(Int(33)))
|
||||
|
||||
fmt.Println(stmt.Sql())
|
||||
|
||||
assertStatementSql(t, stmt, expectedSQL, 1, int64(33))
|
||||
}
|
||||
|
||||
func TestUpdateWithValues(t *testing.T) {
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET (col_int, col_float) = ($1, $2)
|
||||
WHERE table1.col_int >= $3;
|
||||
`
|
||||
stmt := table1.UPDATE(table1ColInt, table1ColFloat).
|
||||
SET(1, 22.2).
|
||||
WHERE(table1ColInt.GT_EQ(Int(33)))
|
||||
|
||||
fmt.Println(stmt.Sql())
|
||||
|
||||
assertStatementSql(t, stmt, expectedSQL, 1, 22.2, int64(33))
|
||||
}
|
||||
|
||||
func TestUpdateOneColumnWithSelect(t *testing.T) {
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET col_float = (
|
||||
SELECT table1.col_float AS "table1.col_float"
|
||||
FROM db.table1
|
||||
)
|
||||
WHERE table1.col1 = $1
|
||||
RETURNING table1.col1 AS "table1.col1";
|
||||
`
|
||||
stmt := table1.
|
||||
UPDATE(table1ColFloat).
|
||||
SET(
|
||||
table1.SELECT(table1ColFloat),
|
||||
).
|
||||
WHERE(table1Col1.EQ(Int(2))).
|
||||
RETURNING(table1Col1)
|
||||
|
||||
assertStatementSql(t, stmt, expectedSQL, int64(2))
|
||||
}
|
||||
|
||||
func TestInvalidInputs(t *testing.T) {
|
||||
assertStatementSqlErr(t, table1.UPDATE(table1ColInt).SET(1), "jet: WHERE clause not set")
|
||||
assertStatementSqlErr(t, table1.UPDATE(nil).SET(1), "jet: nil column in columns list")
|
||||
}
|
||||
83
tools/jet-2.12.0/postgres/utils_test.go
Normal file
83
tools/jet-2.12.0/postgres/utils_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
)
|
||||
|
||||
var table1Col1 = IntegerColumn("col1")
|
||||
var table1ColInt = IntegerColumn("col_int")
|
||||
var table1ColFloat = FloatColumn("col_float")
|
||||
var table1ColTime = TimeColumn("col_time")
|
||||
var table1ColTimez = TimezColumn("col_timez")
|
||||
var table1ColTimestamp = TimestampColumn("col_timestamp")
|
||||
var table1ColTimestampz = TimestampzColumn("col_timestampz")
|
||||
var table1ColBool = BoolColumn("col_bool")
|
||||
var table1ColDate = DateColumn("col_date")
|
||||
var table1ColInterval = IntervalColumn("col_interval")
|
||||
var table1ColRange = Int8RangeColumn("col_range")
|
||||
|
||||
var table1 = NewTable(
|
||||
"db",
|
||||
"table1",
|
||||
"",
|
||||
table1Col1,
|
||||
table1ColInt,
|
||||
table1ColFloat,
|
||||
table1ColTime,
|
||||
table1ColTimez,
|
||||
table1ColBool,
|
||||
table1ColDate,
|
||||
table1ColTimestamp,
|
||||
table1ColTimestampz,
|
||||
table1ColInterval,
|
||||
table1ColRange,
|
||||
)
|
||||
|
||||
var table2Col3 = IntegerColumn("col3")
|
||||
var table2Col4 = IntegerColumn("col4")
|
||||
var table2ColInt = IntegerColumn("col_int")
|
||||
var table2ColFloat = FloatColumn("col_float")
|
||||
var table2ColStr = StringColumn("col_str")
|
||||
var table2ColBool = BoolColumn("col_bool")
|
||||
var table2ColTime = TimeColumn("col_time")
|
||||
var table2ColTimez = TimezColumn("col_timez")
|
||||
var table2ColTimestamp = TimestampColumn("col_timestamp")
|
||||
var table2ColTimestampz = TimestampzColumn("col_timestampz")
|
||||
var table2ColDate = DateColumn("col_date")
|
||||
var table2ColInterval = IntervalColumn("col_interval")
|
||||
var table2ColRange = Int8RangeColumn("col_range")
|
||||
|
||||
var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz, table2ColInterval, table2ColRange)
|
||||
|
||||
var table3Col1 = IntegerColumn("col1")
|
||||
var table3ColInt = IntegerColumn("col_int")
|
||||
var table3StrCol = StringColumn("col2")
|
||||
var table3 = NewTable("db", "table3", "", table3Col1, table3ColInt, table3StrCol)
|
||||
|
||||
func assertSerialize(t *testing.T, serializer jet.Serializer, query string, args ...interface{}) {
|
||||
testutils.AssertSerialize(t, Dialect, serializer, query, args...)
|
||||
}
|
||||
|
||||
func assertDebugSerialize(t *testing.T, serializer jet.Serializer, query string, args ...interface{}) {
|
||||
testutils.AssertDebugSerialize(t, Dialect, serializer, query, args...)
|
||||
}
|
||||
|
||||
func assertClauseSerialize(t *testing.T, clause jet.Clause, query string, args ...interface{}) {
|
||||
testutils.AssertClauseSerialize(t, Dialect, clause, query, args...)
|
||||
}
|
||||
|
||||
func assertSerializeErr(t *testing.T, serializer jet.Serializer, errString string) {
|
||||
testutils.AssertSerializeErr(t, Dialect, serializer, errString)
|
||||
}
|
||||
|
||||
func assertProjectionSerialize(t *testing.T, projection jet.Projection, query string, args ...interface{}) {
|
||||
testutils.AssertProjectionSerialize(t, Dialect, projection, query, args...)
|
||||
}
|
||||
|
||||
var assertStatementSql = testutils.AssertStatementSql
|
||||
var assertDebugStatementSql = testutils.AssertDebugStatementSql
|
||||
var assertStatementSqlErr = testutils.AssertStatementSqlErr
|
||||
var assertPanicErr = testutils.AssertPanicErr
|
||||
32
tools/jet-2.12.0/postgres/values.go
Normal file
32
tools/jet-2.12.0/postgres/values.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
type values struct {
|
||||
jet.Values
|
||||
}
|
||||
|
||||
// VALUES is a table value constructor that computes a set of one or more rows as a temporary constant table.
|
||||
// Each row is defined by the WRAP constructor, which takes one or more expressions.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// VALUES(
|
||||
// WRAP(Int32(204), Real(1.21)),
|
||||
// WRAP(Int32(207), Real(1.02)),
|
||||
// )
|
||||
func VALUES(rows ...RowExpression) values {
|
||||
return values{Values: jet.Values(rows)}
|
||||
}
|
||||
|
||||
// AS assigns an alias to the temporary VALUES table, allowing it to be referenced
|
||||
// within SQL FROM clauses, just like a regular table.
|
||||
// By default, VALUES columns are named `column1`, `column2`, etc... Default column aliasing can be
|
||||
// overwritten by passing new list of columns.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// VALUES(...).AS("film_values", IntegerColumn("length"), TimestampColumn("update_date"))
|
||||
func (v values) AS(alias string, columns ...Column) SelectTable {
|
||||
return newSelectTable(v, alias, columns)
|
||||
}
|
||||
74
tools/jet-2.12.0/postgres/with_statement.go
Normal file
74
tools/jet-2.12.0/postgres/with_statement.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// CommonTableExpression defines set of interface methods for postgres CTEs
|
||||
type CommonTableExpression interface {
|
||||
SelectTable
|
||||
|
||||
AS(statement jet.SerializerHasProjections) CommonTableExpression
|
||||
AS_NOT_MATERIALIZED(statement jet.SerializerStatement) CommonTableExpression
|
||||
// ALIAS is used to create another alias of the CTE, if a CTE needs to appear multiple times in the main query.
|
||||
ALIAS(alias string) SelectTable
|
||||
|
||||
internalCTE() *jet.CommonTableExpression
|
||||
}
|
||||
|
||||
type commonTableExpression struct {
|
||||
readableTableInterfaceImpl
|
||||
jet.CommonTableExpression
|
||||
}
|
||||
|
||||
// WITH function creates new WITH statement from list of common table expressions
|
||||
func WITH(cte ...CommonTableExpression) func(statement jet.Statement) Statement {
|
||||
return jet.WITH(Dialect, false, toInternalCTE(cte)...)
|
||||
}
|
||||
|
||||
// WITH_RECURSIVE function creates new WITH RECURSIVE statement from list of common table expressions
|
||||
func WITH_RECURSIVE(cte ...CommonTableExpression) func(statement jet.Statement) Statement {
|
||||
return jet.WITH(Dialect, true, toInternalCTE(cte)...)
|
||||
}
|
||||
|
||||
// CTE creates new named commonTableExpression
|
||||
func CTE(name string, columns ...jet.ColumnExpression) CommonTableExpression {
|
||||
cte := &commonTableExpression{
|
||||
readableTableInterfaceImpl: readableTableInterfaceImpl{},
|
||||
CommonTableExpression: jet.CTE(name, columns...),
|
||||
}
|
||||
|
||||
cte.parent = cte
|
||||
|
||||
return cte
|
||||
}
|
||||
|
||||
// AS is used to define a CTE query
|
||||
func (c *commonTableExpression) AS(statement jet.SerializerHasProjections) CommonTableExpression {
|
||||
c.CommonTableExpression.Statement = statement
|
||||
return c
|
||||
}
|
||||
|
||||
// AS_NOT_MATERIALIZED is used to define not materialized CTE query
|
||||
func (c *commonTableExpression) AS_NOT_MATERIALIZED(statement jet.SerializerStatement) CommonTableExpression {
|
||||
c.CommonTableExpression.NotMaterialized = true
|
||||
c.CommonTableExpression.Statement = statement
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *commonTableExpression) internalCTE() *jet.CommonTableExpression {
|
||||
return &c.CommonTableExpression
|
||||
}
|
||||
|
||||
// ALIAS is used to create another alias of the CTE, if a CTE needs to appear multiple times in the main query.
|
||||
func (c *commonTableExpression) ALIAS(name string) SelectTable {
|
||||
return newSelectTable(c, name, nil)
|
||||
}
|
||||
|
||||
func toInternalCTE(ctes []CommonTableExpression) []*jet.CommonTableExpression {
|
||||
var ret []*jet.CommonTableExpression
|
||||
|
||||
for _, cte := range ctes {
|
||||
ret = append(ret, cte.internalCTE())
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user