Merge remote-tracking branch 'upstream/master' into stmt-cache2
# Conflicts: # tests/postgres/alltypes_test.go # tests/postgres/northwind_test.go # tests/postgres/sample_test.go # tests/postgres/update_test.go # tests/sqlite/insert_test.go # tests/sqlite/main_test.go # tests/sqlite/sample_test.go # tests/sqlite/update_test.go
This commit is contained in:
commit
4bb9775134
97 changed files with 2306 additions and 537 deletions
|
|
@ -109,13 +109,20 @@ type ColumnInterval interface {
|
|||
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())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
"strconv"
|
||||
)
|
||||
|
|
@ -25,6 +26,9 @@ func newDialect() jet.Dialect {
|
|||
return "$" + strconv.Itoa(ord)
|
||||
},
|
||||
ReservedWords: reservedWords,
|
||||
ValuesDefaultColumnName: func(index int) string {
|
||||
return fmt.Sprintf("column%d", index+1)
|
||||
},
|
||||
}
|
||||
|
||||
return jet.NewDialect(dialectParams)
|
||||
|
|
|
|||
|
|
@ -46,33 +46,33 @@ func TestExists(t *testing.T) {
|
|||
func TestIN(t *testing.T) {
|
||||
|
||||
assertSerialize(t, Float(1.11).IN(table1.SELECT(table1Col1)),
|
||||
`($1 IN (
|
||||
`($1 IN ((
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
))`, float64(1.11))
|
||||
)))`, float64(1.11))
|
||||
|
||||
assertSerialize(t, ROW(Int(12), table1Col1).IN(table2.SELECT(table2Col3, table3Col1)),
|
||||
`(ROW($1, table1.col1) IN (
|
||||
`(ROW($1, table1.col1) IN ((
|
||||
SELECT table2.col3 AS "table2.col3",
|
||||
table3.col1 AS "table3.col1"
|
||||
FROM db.table2
|
||||
))`, int64(12))
|
||||
)))`, int64(12))
|
||||
}
|
||||
|
||||
func TestNOT_IN(t *testing.T) {
|
||||
|
||||
assertSerialize(t, Float(1.11).NOT_IN(table1.SELECT(table1Col1)),
|
||||
`($1 NOT IN (
|
||||
`($1 NOT IN ((
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
))`, float64(1.11))
|
||||
)))`, float64(1.11))
|
||||
|
||||
assertSerialize(t, ROW(Int(12), table1Col1).NOT_IN(table2.SELECT(table2Col3, table3Col1)),
|
||||
`(ROW($1, table1.col1) NOT IN (
|
||||
`(ROW($1, table1.col1) NOT IN ((
|
||||
SELECT table2.col3 AS "table2.col3",
|
||||
table3.col1 AS "table3.col1"
|
||||
FROM db.table2
|
||||
))`, int64(12))
|
||||
)))`, int64(12))
|
||||
}
|
||||
|
||||
func TestReservedWordEscaped(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ type TimestampExpression = jet.TimestampExpression
|
|||
// TimestampzExpression interface
|
||||
type TimestampzExpression = jet.TimestampzExpression
|
||||
|
||||
// RowExpression interface
|
||||
type RowExpression = jet.RowExpression
|
||||
|
||||
// DateRange Expression interface
|
||||
type DateRange = jet.Range[DateExpression]
|
||||
|
||||
|
|
@ -99,6 +102,11 @@ var TimestampExp = jet.TimestampExp
|
|||
// 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.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ var (
|
|||
)
|
||||
|
||||
// ROW function is used to create a tuple value that consists of a set of expressions or column values.
|
||||
var ROW = jet.ROW
|
||||
func ROW(expressions ...Expression) RowExpression {
|
||||
return jet.ROW(Dialect, expressions...)
|
||||
}
|
||||
|
||||
// ------------------ Mathematical functions ---------------//
|
||||
|
||||
|
|
@ -332,6 +334,16 @@ 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)
|
||||
}
|
||||
|
||||
// --------------- Conditional Expressions Functions -------------//
|
||||
|
||||
// COALESCE function returns the first of its arguments that is not null.
|
||||
|
|
@ -415,10 +427,12 @@ func castFloatLiteral(fraction FloatExpression) FloatExpression {
|
|||
// ),
|
||||
var GROUPING_SETS = jet.GROUPING_SETS
|
||||
|
||||
// WRAP wraps list of expressions with brackets - ( expression1, expression2, ... )
|
||||
// The construct (a, b) is normally recognized in expressions as a row constructor. WRAP and ROW method behave exactly the same,
|
||||
// except when used in GROUPING_SETS. For top level GROUPING SETS expression lists WRAP has to be used.
|
||||
var WRAP = jet.WRAP
|
||||
// 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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package postgres
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestROW(t *testing.T) {
|
||||
assertSerialize(t, ROW(SELECT(Int(1))), `ROW((
|
||||
|
|
@ -10,3 +12,12 @@ func TestROW(t *testing.T) {
|
|||
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')",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/jet"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -151,12 +150,13 @@ func TestInsert_ON_CONFLICT(t *testing.T) {
|
|||
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))),
|
||||
).
|
||||
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, `
|
||||
|
|
@ -178,12 +178,12 @@ 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(jet.ROW(Int(2), String("two"))),
|
||||
).WHERE(table1Col1.GT(Int(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, `
|
||||
|
|
|
|||
|
|
@ -57,6 +57,16 @@ func Uint64(value uint64) IntegerExpression {
|
|||
// Float creates new float literal expression
|
||||
var Float = jet.Float
|
||||
|
||||
// Float32 is constructor for 32 bit float literals
|
||||
func Float32(value float32) FloatExpression {
|
||||
return CAST(jet.Literal(value)).AS_REAL()
|
||||
}
|
||||
|
||||
// Float64 is constructor for 64 bit float literals
|
||||
func Float64(value float64) FloatExpression {
|
||||
return CAST(jet.Literal(value)).AS_DOUBLE()
|
||||
}
|
||||
|
||||
// Decimal creates new float literal expression
|
||||
var Decimal = jet.Decimal
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ func (s *selectStatementImpl) FOR(lock RowLock) SelectStatement {
|
|||
}
|
||||
|
||||
func (s *selectStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s, alias)
|
||||
return newSelectTable(s, alias, nil)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package postgres
|
|||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
// SelectTable is interface for postgres sub-queries
|
||||
// SelectTable is interface for postgres temporary tables like sub-queries, VALUES, CTEs etc...
|
||||
type SelectTable interface {
|
||||
readableTable
|
||||
jet.SelectTable
|
||||
|
|
@ -13,9 +13,9 @@ type selectTableImpl struct {
|
|||
readableTableInterfaceImpl
|
||||
}
|
||||
|
||||
func newSelectTable(selectStmt jet.SerializerHasProjections, alias string) SelectTable {
|
||||
func newSelectTable(serializerWithProjections jet.SerializerHasProjections, alias string, columnAliases []jet.ColumnExpression) SelectTable {
|
||||
subQuery := &selectTableImpl{
|
||||
SelectTable: jet.NewSelectTable(selectStmt, alias),
|
||||
SelectTable: jet.NewSelectTable(serializerWithProjections, alias, columnAliases),
|
||||
}
|
||||
|
||||
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ func (s *setStatementImpl) OFFSET_e(offset IntegerExpression) setStatement {
|
|||
}
|
||||
|
||||
func (s *setStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s, alias)
|
||||
return newSelectTable(s, alias, nil)
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
|||
32
postgres/values.go
Normal file
32
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), Float32(1.21)),
|
||||
// WRAP(Int32(207), Float32(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)
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import "github.com/go-jet/jet/v2/internal/jet"
|
|||
type CommonTableExpression interface {
|
||||
SelectTable
|
||||
|
||||
AS(statement jet.SerializerStatement) CommonTableExpression
|
||||
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
|
||||
|
|
@ -42,7 +42,7 @@ func CTE(name string, columns ...jet.ColumnExpression) CommonTableExpression {
|
|||
}
|
||||
|
||||
// AS is used to define a CTE query
|
||||
func (c *commonTableExpression) AS(statement jet.SerializerStatement) CommonTableExpression {
|
||||
func (c *commonTableExpression) AS(statement jet.SerializerHasProjections) CommonTableExpression {
|
||||
c.CommonTableExpression.Statement = statement
|
||||
return c
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ func (c *commonTableExpression) internalCTE() *jet.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)
|
||||
return newSelectTable(c, name, nil)
|
||||
}
|
||||
|
||||
func toInternalCTE(ctes []CommonTableExpression) []*jet.CommonTableExpression {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue