Merge pull request #419 from go-jet/str-constr
Add PostgreSQL-specific character type constructors: Text, Char, and VarChar
This commit is contained in:
commit
f8f2f75a0d
13 changed files with 231 additions and 286 deletions
16
README.md
16
README.md
|
|
@ -175,9 +175,9 @@ stmt := SELECT(
|
||||||
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
|
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
|
||||||
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
|
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
|
||||||
).WHERE(
|
).WHERE(
|
||||||
Language.Name.EQ(String("English")).
|
Language.Name.EQ(Char(20)("English")).
|
||||||
AND(Category.Name.NOT_EQ(String("Action"))).
|
AND(Category.Name.NOT_EQ(Text("Action"))).
|
||||||
AND(Film.Length.GT(Int(180))),
|
AND(Film.Length.GT(Int32(180))),
|
||||||
).ORDER_BY(
|
).ORDER_BY(
|
||||||
Actor.ActorID.ASC(),
|
Actor.ActorID.ASC(),
|
||||||
Film.FilmID.ASC(),
|
Film.FilmID.ASC(),
|
||||||
|
|
@ -228,7 +228,7 @@ FROM dvds.actor
|
||||||
INNER JOIN dvds.language ON (language.language_id = film.language_id)
|
INNER JOIN dvds.language ON (language.language_id = film.language_id)
|
||||||
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
|
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
|
||||||
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
|
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
|
||||||
WHERE ((language.name = $1) AND (category.name != $2)) AND (film.length > $3)
|
WHERE ((language.name = $1::char(20)) AND (category.name != $2::text)) AND (film.length > $3::integer)
|
||||||
ORDER BY actor.actor_id ASC, film.film_id ASC;
|
ORDER BY actor.actor_id ASC, film.film_id ASC;
|
||||||
```
|
```
|
||||||
```sh
|
```sh
|
||||||
|
|
@ -277,7 +277,7 @@ FROM dvds.actor
|
||||||
INNER JOIN dvds.language ON (language.language_id = film.language_id)
|
INNER JOIN dvds.language ON (language.language_id = film.language_id)
|
||||||
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
|
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
|
||||||
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
|
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
|
||||||
WHERE ((language.name = 'English') AND (category.name != 'Action')) AND (film.length > 180)
|
WHERE ((language.name = 'English'::char(20)) AND (category.name != 'Action'::text)) AND (film.length > 180::integer)
|
||||||
ORDER BY actor.actor_id ASC, film.film_id ASC;
|
ORDER BY actor.actor_id ASC, film.film_id ASC;
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
@ -545,18 +545,18 @@ The most expensive bugs are the one discovered on the production, and the least
|
||||||
With automatically generated type safe SQL, not only queries are written faster but bugs are found sooner.
|
With automatically generated type safe SQL, not only queries are written faster but bugs are found sooner.
|
||||||
Let's return to quick start example, and take closer look at a line:
|
Let's return to quick start example, and take closer look at a line:
|
||||||
```go
|
```go
|
||||||
AND(Film.Length.GT(Int(180))),
|
AND(Film.Length.GT(Int32(180))),
|
||||||
```
|
```
|
||||||
Let's say someone changes column `length` to `duration` from `film` table. The next go build will fail at that line, and
|
Let's say someone changes column `length` to `duration` from `film` table. The next go build will fail at that line, and
|
||||||
the bug will be caught at compile time.
|
the bug will be caught at compile time.
|
||||||
|
|
||||||
Let's say someone changes the type of `length` column to some non integer type. Build will also fail at the same line
|
Let's say someone changes the type of `length` column to some non-integer type. Build will also fail at the same line
|
||||||
because integer columns and expressions can be only compared to other integer columns and expressions.
|
because integer columns and expressions can be only compared to other integer columns and expressions.
|
||||||
|
|
||||||
Build will also fail if someone removes `length` column from `film` table. `Film` field will be omitted from SQL Builder and Model types,
|
Build will also fail if someone removes `length` column from `film` table. `Film` field will be omitted from SQL Builder and Model types,
|
||||||
next time `jet` generator is run.
|
next time `jet` generator is run.
|
||||||
|
|
||||||
Without Jet these bugs will have to be either caught by some test or by manual testing.
|
Without Jet these bugs will have to be either caught by tests or by manual testing.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
At the moment Jet dependence only of:
|
At the moment Jet dependence only of:
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ func main() {
|
||||||
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
|
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
|
||||||
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
|
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
|
||||||
).WHERE(
|
).WHERE(
|
||||||
Language.Name.EQ(String("English")).
|
Language.Name.EQ(Char(20)("English")).
|
||||||
AND(Category.Name.NOT_EQ(String("Action"))).
|
AND(Category.Name.NOT_EQ(Text("Action"))).
|
||||||
AND(Film.Length.GT(Int(180))),
|
AND(Film.Length.GT(Int(180))),
|
||||||
).ORDER_BY(
|
).ORDER_BY(
|
||||||
Actor.ActorID.ASC(),
|
Actor.ActorID.ASC(),
|
||||||
|
|
|
||||||
8
go.mod
8
go.mod
|
|
@ -1,19 +1,21 @@
|
||||||
module github.com/go-jet/jet/v2
|
module github.com/go-jet/jet/v2
|
||||||
|
|
||||||
go 1.20
|
go 1.21
|
||||||
|
|
||||||
|
// used by jet generator
|
||||||
require (
|
require (
|
||||||
github.com/go-sql-driver/mysql v1.8.1
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
github.com/google/go-cmp v0.6.0
|
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/jackc/pgconn v1.14.3
|
github.com/jackc/pgconn v1.14.3
|
||||||
github.com/jackc/pgtype v1.14.3
|
github.com/jackc/pgtype v1.14.4
|
||||||
github.com/jackc/pgx/v4 v4.18.3
|
github.com/jackc/pgx/v4 v4.18.3
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/mattn/go-sqlite3 v1.14.24
|
github.com/mattn/go-sqlite3 v1.14.24
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// used in tests
|
||||||
require (
|
require (
|
||||||
|
github.com/google/go-cmp v0.6.0
|
||||||
github.com/pkg/profile v1.7.0
|
github.com/pkg/profile v1.7.0
|
||||||
github.com/shopspring/decimal v1.4.0
|
github.com/shopspring/decimal v1.4.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -71,8 +71,8 @@ github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCM
|
||||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||||
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||||
github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus=
|
github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8=
|
||||||
github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
|
github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||||
|
|
|
||||||
|
|
@ -5,66 +5,40 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cast interface {
|
type cast struct {
|
||||||
// AS casts expressions as castType type
|
|
||||||
AS(castType string) Expression
|
|
||||||
// AS_CHAR casts expression as char with optional length
|
|
||||||
AS_CHAR(length ...int) StringExpression
|
|
||||||
// AS_DATE casts expression AS date type
|
|
||||||
AS_DATE() DateExpression
|
|
||||||
// AS_FLOAT casts expressions as float type
|
|
||||||
AS_FLOAT() FloatExpression
|
|
||||||
// AS_DOUBLE casts expressions as double type
|
|
||||||
AS_DOUBLE() FloatExpression
|
|
||||||
// AS_DECIMAL casts expression AS numeric type
|
|
||||||
AS_DECIMAL() FloatExpression
|
|
||||||
// AS_TIME casts expression AS time type
|
|
||||||
AS_TIME() TimeExpression
|
|
||||||
// AS_DATETIME casts expression as datetime type
|
|
||||||
AS_DATETIME() DateTimeExpression
|
|
||||||
// AS_SIGNED casts expressions as signed integer type
|
|
||||||
AS_SIGNED() IntegerExpression
|
|
||||||
// AS_UNSIGNED casts expression as unsigned integer type
|
|
||||||
AS_UNSIGNED() IntegerExpression
|
|
||||||
// AS_BINARY casts expression as binary type
|
|
||||||
AS_BINARY() StringExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
type castImpl struct {
|
|
||||||
jet.Cast
|
jet.Cast
|
||||||
}
|
}
|
||||||
|
|
||||||
// CAST function converts a expr (of any type) into latter specified datatype.
|
// CAST function converts a expr (of any type) into latter specified datatype.
|
||||||
func CAST(expr Expression) cast {
|
func CAST(expr Expression) *cast {
|
||||||
castImpl := &castImpl{}
|
ret := &cast{}
|
||||||
|
ret.Cast = jet.NewCastImpl(expr)
|
||||||
|
|
||||||
castImpl.Cast = jet.NewCastImpl(expr)
|
return ret
|
||||||
|
|
||||||
return castImpl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS casts expressions to castType
|
// AS casts expressions to castType
|
||||||
func (c *castImpl) AS(castType string) Expression {
|
func (c *cast) AS(castType string) Expression {
|
||||||
return c.Cast.AS(castType)
|
return c.Cast.AS(castType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_DATETIME cast expression to DATETIME type
|
// AS_DATETIME cast expression to DATETIME type
|
||||||
func (c *castImpl) AS_DATETIME() DateTimeExpression {
|
func (c *cast) AS_DATETIME() DateTimeExpression {
|
||||||
return DateTimeExp(c.AS("DATETIME"))
|
return DateTimeExp(c.AS("DATETIME"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_SIGNED casts expression to SIGNED type
|
// AS_SIGNED casts expression to SIGNED type
|
||||||
func (c *castImpl) AS_SIGNED() IntegerExpression {
|
func (c *cast) AS_SIGNED() IntegerExpression {
|
||||||
return IntExp(c.AS("SIGNED"))
|
return IntExp(c.AS("SIGNED"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_UNSIGNED casts expression to UNSIGNED type
|
// AS_UNSIGNED casts expression to UNSIGNED type
|
||||||
func (c *castImpl) AS_UNSIGNED() IntegerExpression {
|
func (c *cast) AS_UNSIGNED() IntegerExpression {
|
||||||
return IntExp(c.AS("UNSIGNED"))
|
return IntExp(c.AS("UNSIGNED"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_CHAR casts expression to CHAR type with optional length
|
// AS_CHAR casts expression to CHAR type with optional length
|
||||||
func (c *castImpl) AS_CHAR(length ...int) StringExpression {
|
func (c *cast) AS_CHAR(length ...int) StringExpression {
|
||||||
if len(length) > 0 {
|
if len(length) > 0 {
|
||||||
return StringExp(c.AS("CHAR(" + strconv.Itoa(length[0]) + ")"))
|
return StringExp(c.AS("CHAR(" + strconv.Itoa(length[0]) + ")"))
|
||||||
}
|
}
|
||||||
|
|
@ -73,29 +47,29 @@ func (c *castImpl) AS_CHAR(length ...int) StringExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_DATE casts expression AS DATE type
|
// AS_DATE casts expression AS DATE type
|
||||||
func (c *castImpl) AS_DATE() DateExpression {
|
func (c *cast) AS_DATE() DateExpression {
|
||||||
return DateExp(c.AS("DATE"))
|
return DateExp(c.AS("DATE"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *castImpl) AS_FLOAT() FloatExpression {
|
func (c *cast) AS_FLOAT() FloatExpression {
|
||||||
return FloatExp(c.AS("FLOAT"))
|
return FloatExp(c.AS("FLOAT"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *castImpl) AS_DOUBLE() FloatExpression {
|
func (c *cast) AS_DOUBLE() FloatExpression {
|
||||||
return FloatExp(c.AS("DOUBLE"))
|
return FloatExp(c.AS("DOUBLE"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_DECIMAL casts expression AS DECIMAL type
|
// AS_DECIMAL casts expression AS DECIMAL type
|
||||||
func (c *castImpl) AS_DECIMAL() FloatExpression {
|
func (c *cast) AS_DECIMAL() FloatExpression {
|
||||||
return FloatExp(c.AS("DECIMAL"))
|
return FloatExp(c.AS("DECIMAL"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_TIME casts expression AS TIME type
|
// AS_TIME casts expression AS TIME type
|
||||||
func (c *castImpl) AS_TIME() TimeExpression {
|
func (c *cast) AS_TIME() TimeExpression {
|
||||||
return TimeExp(c.AS("TIME"))
|
return TimeExp(c.AS("TIME"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_BINARY casts expression as BINARY type
|
// AS_BINARY casts expression as BINARY type
|
||||||
func (c *castImpl) AS_BINARY() StringExpression {
|
func (c *cast) AS_BINARY() StringExpression {
|
||||||
return StringExp(c.AS("BINARY"))
|
return StringExp(c.AS("BINARY"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
131
postgres/cast.go
131
postgres/cast.go
|
|
@ -7,84 +7,45 @@ import (
|
||||||
"github.com/go-jet/jet/v2/internal/jet"
|
"github.com/go-jet/jet/v2/internal/jet"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cast interface {
|
type cast struct {
|
||||||
AS(castType string) Expression
|
|
||||||
// Cast expression AS bool type
|
|
||||||
AS_BOOL() BoolExpression
|
|
||||||
// Cast expression AS smallint type
|
|
||||||
AS_SMALLINT() IntegerExpression
|
|
||||||
// Cast expression AS integer type
|
|
||||||
AS_INTEGER() IntegerExpression
|
|
||||||
// Cast expression AS bigint type
|
|
||||||
AS_BIGINT() IntegerExpression
|
|
||||||
// Cast expression AS numeric type, using precision and optionally scale
|
|
||||||
AS_NUMERIC(precisionAndScale ...int) FloatExpression
|
|
||||||
// Cast expression AS real type
|
|
||||||
AS_REAL() FloatExpression
|
|
||||||
// Cast expression AS double precision type
|
|
||||||
AS_DOUBLE() FloatExpression
|
|
||||||
// Cast expression AS char with optional length
|
|
||||||
AS_CHAR(length ...int) StringExpression
|
|
||||||
// Cast expression AS date type
|
|
||||||
AS_DATE() DateExpression
|
|
||||||
// Cast expression AS numeric type, using precision and optionally scale
|
|
||||||
AS_DECIMAL() FloatExpression
|
|
||||||
// Cast expression AS time type
|
|
||||||
AS_TIME() TimeExpression
|
|
||||||
// Cast expression AS text type
|
|
||||||
AS_TEXT() StringExpression
|
|
||||||
// Cast expression AS bytea type
|
|
||||||
AS_BYTEA() StringExpression
|
|
||||||
// Cast expression AS time with time timezone type
|
|
||||||
AS_TIMEZ() TimezExpression
|
|
||||||
// Cast expression AS timestamp type
|
|
||||||
AS_TIMESTAMP() TimestampExpression
|
|
||||||
// Cast expression AS timestamp with timezone type
|
|
||||||
AS_TIMESTAMPZ() TimestampzExpression
|
|
||||||
// Cast expression AS interval type
|
|
||||||
AS_INTERVAL() IntervalExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
type castImpl struct {
|
|
||||||
jet.Cast
|
jet.Cast
|
||||||
}
|
}
|
||||||
|
|
||||||
// CAST function converts a expr (of any type) into latter specified datatype.
|
// CAST function converts an expr (of any type) into later specified datatype.
|
||||||
func CAST(expr Expression) cast {
|
func CAST(expr Expression) *cast {
|
||||||
castImpl := &castImpl{}
|
ret := &cast{}
|
||||||
|
ret.Cast = jet.NewCastImpl(expr)
|
||||||
|
|
||||||
castImpl.Cast = jet.NewCastImpl(expr)
|
return ret
|
||||||
|
|
||||||
return castImpl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression as castType
|
// AS casts expression as castType
|
||||||
func (b *castImpl) AS(castType string) Expression {
|
func (b *cast) AS(castType string) Expression {
|
||||||
return b.Cast.AS(castType)
|
return b.Cast.AS(castType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression as bool type
|
// AS_BOOL casts expression as bool type
|
||||||
func (b *castImpl) AS_BOOL() BoolExpression {
|
func (b *cast) AS_BOOL() BoolExpression {
|
||||||
return BoolExp(b.AS("boolean"))
|
return BoolExp(b.AS("boolean"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression as smallint type
|
// AS_SMALLINT casts expression as smallint type
|
||||||
func (b *castImpl) AS_SMALLINT() IntegerExpression {
|
func (b *cast) AS_SMALLINT() IntegerExpression {
|
||||||
return IntExp(b.AS("smallint"))
|
return IntExp(b.AS("smallint"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS integer type
|
// AS_INTEGER casts expression AS integer type
|
||||||
func (b *castImpl) AS_INTEGER() IntegerExpression {
|
func (b *cast) AS_INTEGER() IntegerExpression {
|
||||||
return IntExp(b.AS("integer"))
|
return IntExp(b.AS("integer"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS bigint type
|
// AS_BIGINT casts expression AS bigint type
|
||||||
func (b *castImpl) AS_BIGINT() IntegerExpression {
|
func (b *cast) AS_BIGINT() IntegerExpression {
|
||||||
return IntExp(b.AS("bigint"))
|
return IntExp(b.AS("bigint"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS numeric type, using precision and optionally scale
|
// AS_NUMERIC casts expression as numeric type, using precision and optionally scale
|
||||||
func (b *castImpl) AS_NUMERIC(precisionAndScale ...int) FloatExpression {
|
func (b *cast) AS_NUMERIC(precisionAndScale ...int) FloatExpression {
|
||||||
var castArgs string
|
var castArgs string
|
||||||
|
|
||||||
var argLen = len(precisionAndScale)
|
var argLen = len(precisionAndScale)
|
||||||
|
|
@ -97,22 +58,23 @@ func (b *castImpl) AS_NUMERIC(precisionAndScale ...int) FloatExpression {
|
||||||
return FloatExp(b.AS("numeric" + castArgs))
|
return FloatExp(b.AS("numeric" + castArgs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS real type
|
// AS_REAL casts expression AS real type
|
||||||
func (b *castImpl) AS_REAL() FloatExpression {
|
func (b *cast) AS_REAL() FloatExpression {
|
||||||
return FloatExp(b.AS("real"))
|
return FloatExp(b.AS("real"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS double precision type
|
// AS_DOUBLE casts expression AS double precision type
|
||||||
func (b *castImpl) AS_DOUBLE() FloatExpression {
|
func (b *cast) AS_DOUBLE() FloatExpression {
|
||||||
return FloatExp(b.AS("double precision"))
|
return FloatExp(b.AS("double precision"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS text type
|
// AS_TEXT casts expression AS text type
|
||||||
func (b *castImpl) AS_TEXT() StringExpression {
|
func (b *cast) AS_TEXT() StringExpression {
|
||||||
return StringExp(b.AS("text"))
|
return StringExp(b.AS("text"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *castImpl) AS_CHAR(length ...int) StringExpression {
|
// AS_CHAR casts expression AS a character type
|
||||||
|
func (b *cast) AS_CHAR(length ...int) StringExpression {
|
||||||
if len(length) > 0 {
|
if len(length) > 0 {
|
||||||
return StringExp(b.AS("char(" + strconv.Itoa(length[0]) + ")"))
|
return StringExp(b.AS("char(" + strconv.Itoa(length[0]) + ")"))
|
||||||
}
|
}
|
||||||
|
|
@ -120,42 +82,51 @@ func (b *castImpl) AS_CHAR(length ...int) StringExpression {
|
||||||
return StringExp(b.AS("char"))
|
return StringExp(b.AS("char"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS date type
|
// AS_VARCHAR casts expression AS a character varying type
|
||||||
func (b *castImpl) AS_DATE() DateExpression {
|
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"))
|
return DateExp(b.AS("date"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS date type
|
// AS_DECIMAL casts expression AS date type
|
||||||
func (b *castImpl) AS_DECIMAL() FloatExpression {
|
func (b *cast) AS_DECIMAL() FloatExpression {
|
||||||
return FloatExp(b.AS("decimal"))
|
return FloatExp(b.AS("decimal"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS text type
|
// AS_BYTEA casts expression AS text type
|
||||||
func (b *castImpl) AS_BYTEA() StringExpression {
|
func (b *cast) AS_BYTEA() StringExpression {
|
||||||
return StringExp(b.AS("bytea"))
|
return StringExp(b.AS("bytea"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS date type
|
// AS_TIME casts expression AS date type
|
||||||
func (b *castImpl) AS_TIME() TimeExpression {
|
func (b *cast) AS_TIME() TimeExpression {
|
||||||
return TimeExp(b.AS("time without time zone"))
|
return TimeExp(b.AS("time without time zone"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS time with time timezone type
|
// AS_TIMEZ casts expression AS time with time timezone type
|
||||||
func (b *castImpl) AS_TIMEZ() TimezExpression {
|
func (b *cast) AS_TIMEZ() TimezExpression {
|
||||||
return TimezExp(b.AS("time with time zone"))
|
return TimezExp(b.AS("time with time zone"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS timestamp type
|
// AS_TIMESTAMP casts expression AS timestamp type
|
||||||
func (b *castImpl) AS_TIMESTAMP() TimestampExpression {
|
func (b *cast) AS_TIMESTAMP() TimestampExpression {
|
||||||
return TimestampExp(b.AS("timestamp without time zone"))
|
return TimestampExp(b.AS("timestamp without time zone"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS timestamp with timezone type
|
// AS_TIMESTAMPZ casts expression AS timestamp with timezone type
|
||||||
func (b *castImpl) AS_TIMESTAMPZ() TimestampzExpression {
|
func (b *cast) AS_TIMESTAMPZ() TimestampzExpression {
|
||||||
return TimestampzExp(b.AS("timestamp with time zone"))
|
return TimestampzExp(b.AS("timestamp with time zone"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast expression AS interval type
|
// AS_INTERVAL casts expression AS interval type
|
||||||
func (b *castImpl) AS_INTERVAL() IntervalExpression {
|
func (b *cast) AS_INTERVAL() IntervalExpression {
|
||||||
return IntervalExp(b.AS("interval"))
|
return IntervalExp(b.AS("interval"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,47 +34,64 @@ func Int64(value int64) IntegerExpression {
|
||||||
return CAST(jet.Int(value)).AS_BIGINT()
|
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64 is constructor for 64 bit unsigned integer expressions literals.
|
|
||||||
func Uint64(value uint64) IntegerExpression {
|
|
||||||
return CAST(jet.Uint64(value)).AS_BIGINT()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float creates new float literal expression
|
// Float creates new float literal expression
|
||||||
var Float = jet.Float
|
var Float = jet.Float
|
||||||
|
|
||||||
// Float32 is constructor for 32 bit float literals
|
// Real is placeholder constructor for 32-bit float literals
|
||||||
func Float32(value float32) FloatExpression {
|
func Real(value float32) FloatExpression {
|
||||||
return CAST(jet.Literal(value)).AS_REAL()
|
return CAST(jet.Literal(value)).AS_REAL()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float64 is constructor for 64 bit float literals
|
// Double is placeholder constructor for 64-bit float literals
|
||||||
func Float64(value float64) FloatExpression {
|
func Double(value float64) FloatExpression {
|
||||||
return CAST(jet.Literal(value)).AS_DOUBLE()
|
return CAST(jet.Literal(value)).AS_DOUBLE()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decimal creates new float literal expression
|
// Decimal creates new float literal expression
|
||||||
var Decimal = jet.Decimal
|
var Decimal = jet.Decimal
|
||||||
|
|
||||||
// String creates new string literal expression
|
// 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 {
|
func String(value string) StringExpression {
|
||||||
return CAST(jet.String(value)).AS_TEXT()
|
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
|
// Json creates new json literal expression
|
||||||
func Json(value interface{}) StringExpression {
|
func Json(value interface{}) StringExpression {
|
||||||
switch value.(type) {
|
switch value.(type) {
|
||||||
|
|
|
||||||
|
|
@ -34,32 +34,21 @@ func TestInt64(t *testing.T) {
|
||||||
assertSerialize(t, Int64(val), `$1::bigint`, val)
|
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 TestUint64(t *testing.T) {
|
|
||||||
val := uint64(math.MaxUint64)
|
|
||||||
assertSerialize(t, Uint64(val), `$1::bigint`, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFloat(t *testing.T) {
|
func TestFloat(t *testing.T) {
|
||||||
assertSerialize(t, Float(12.34), `$1`, float64(12.34))
|
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) {
|
func TestString(t *testing.T) {
|
||||||
assertSerialize(t, String("Some text"), `$1::text`, "Some text")
|
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) {
|
func TestBytea(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ type values struct {
|
||||||
// Example usage:
|
// Example usage:
|
||||||
//
|
//
|
||||||
// VALUES(
|
// VALUES(
|
||||||
// WRAP(Int32(204), Float32(1.21)),
|
// WRAP(Int32(204), Real(1.21)),
|
||||||
// WRAP(Int32(207), Float32(1.02)),
|
// WRAP(Int32(207), Real(1.02)),
|
||||||
// )
|
// )
|
||||||
func VALUES(rows ...RowExpression) values {
|
func VALUES(rows ...RowExpression) values {
|
||||||
return values{Values: jet.Values(rows)}
|
return values{Values: jet.Values(rows)}
|
||||||
|
|
|
||||||
|
|
@ -4,52 +4,44 @@ import (
|
||||||
"github.com/go-jet/jet/v2/internal/jet"
|
"github.com/go-jet/jet/v2/internal/jet"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cast interface {
|
type cast struct {
|
||||||
AS(castType string) Expression
|
|
||||||
AS_TEXT() StringExpression
|
|
||||||
AS_NUMERIC() FloatExpression
|
|
||||||
AS_INTEGER() IntegerExpression
|
|
||||||
AS_REAL() FloatExpression
|
|
||||||
AS_BLOB() StringExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
type castImpl struct {
|
|
||||||
jet.Cast
|
jet.Cast
|
||||||
}
|
}
|
||||||
|
|
||||||
// CAST function converts a expr (of any type) into latter specified datatype.
|
// CAST function converts a expr (of any type) into latter specified datatype.
|
||||||
func CAST(expr Expression) cast {
|
func CAST(expr Expression) *cast {
|
||||||
castImpl := &castImpl{}
|
ret := &cast{}
|
||||||
castImpl.Cast = jet.NewCastImpl(expr)
|
ret.Cast = jet.NewCastImpl(expr)
|
||||||
return castImpl
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS casts expressions to castType
|
// AS casts expressions to castType
|
||||||
func (c *castImpl) AS(castType string) Expression {
|
func (c *cast) AS(castType string) Expression {
|
||||||
return c.Cast.AS(castType)
|
return c.Cast.AS(castType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_TEXT cast expression to TEXT type
|
// AS_TEXT cast expression to TEXT type
|
||||||
func (c *castImpl) AS_TEXT() StringExpression {
|
func (c *cast) AS_TEXT() StringExpression {
|
||||||
return StringExp(c.AS("TEXT"))
|
return StringExp(c.AS("TEXT"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_NUMERIC cast expression to NUMERIC type
|
// AS_NUMERIC cast expression to NUMERIC type
|
||||||
func (c *castImpl) AS_NUMERIC() FloatExpression {
|
func (c *cast) AS_NUMERIC() FloatExpression {
|
||||||
return FloatExp(c.AS("NUMERIC"))
|
return FloatExp(c.AS("NUMERIC"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_INTEGER cast expression to INTEGER type
|
// AS_INTEGER cast expression to INTEGER type
|
||||||
func (c *castImpl) AS_INTEGER() IntegerExpression {
|
func (c *cast) AS_INTEGER() IntegerExpression {
|
||||||
return IntExp(c.AS("INTEGER"))
|
return IntExp(c.AS("INTEGER"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_REAL cast expression to REAL type
|
// AS_REAL cast expression to REAL type
|
||||||
func (c *castImpl) AS_REAL() FloatExpression {
|
func (c *cast) AS_REAL() FloatExpression {
|
||||||
return FloatExp(c.AS("REAL"))
|
return FloatExp(c.AS("REAL"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AS_BLOB cast expression to BLOB type
|
// AS_BLOB cast expression to BLOB type
|
||||||
func (c *castImpl) AS_BLOB() StringExpression {
|
func (c *cast) AS_BLOB() StringExpression {
|
||||||
return StringExp(c.AS("BLOB"))
|
return StringExp(c.AS("BLOB"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -462,15 +462,15 @@ func TestStringOperators(t *testing.T) {
|
||||||
|
|
||||||
query := AllTypes.SELECT(
|
query := AllTypes.SELECT(
|
||||||
AllTypes.Text.EQ(AllTypes.Char),
|
AllTypes.Text.EQ(AllTypes.Char),
|
||||||
AllTypes.Text.EQ(String("Text")),
|
AllTypes.Text.EQ(Text("Text")),
|
||||||
AllTypes.Text.NOT_EQ(AllTypes.VarCharPtr),
|
AllTypes.Text.NOT_EQ(AllTypes.VarCharPtr),
|
||||||
AllTypes.Text.NOT_EQ(String("Text")),
|
AllTypes.Text.NOT_EQ(Text("Text")),
|
||||||
AllTypes.Text.GT(AllTypes.Text),
|
AllTypes.Text.GT(AllTypes.Text),
|
||||||
AllTypes.Text.GT(String("Text")),
|
AllTypes.Text.GT(Text("Text")),
|
||||||
AllTypes.Text.GT_EQ(AllTypes.TextPtr),
|
AllTypes.Text.GT_EQ(AllTypes.TextPtr),
|
||||||
AllTypes.Text.GT_EQ(String("Text")),
|
AllTypes.Text.GT_EQ(Text("Text")),
|
||||||
AllTypes.Text.LT(AllTypes.Char),
|
AllTypes.Text.LT(AllTypes.Char),
|
||||||
AllTypes.Text.LT(String("Text")),
|
AllTypes.Text.LT(Text("Text")),
|
||||||
AllTypes.Text.LT_EQ(AllTypes.VarChar),
|
AllTypes.Text.LT_EQ(AllTypes.VarChar),
|
||||||
AllTypes.Text.LT_EQ(String("Text")),
|
AllTypes.Text.LT_EQ(String("Text")),
|
||||||
AllTypes.Text.BETWEEN(String("min"), String("max")),
|
AllTypes.Text.BETWEEN(String("min"), String("max")),
|
||||||
|
|
@ -490,13 +490,13 @@ func TestStringOperators(t *testing.T) {
|
||||||
OCTET_LENGTH(AllTypes.Text),
|
OCTET_LENGTH(AllTypes.Text),
|
||||||
OCTET_LENGTH(String("length")),
|
OCTET_LENGTH(String("length")),
|
||||||
LOWER(AllTypes.VarCharPtr),
|
LOWER(AllTypes.VarCharPtr),
|
||||||
LOWER(String("length")),
|
LOWER(Char(4)("length")),
|
||||||
UPPER(AllTypes.Char),
|
UPPER(AllTypes.Char),
|
||||||
UPPER(String("upper")),
|
UPPER(VarChar()("upper")),
|
||||||
BTRIM(AllTypes.VarChar),
|
BTRIM(AllTypes.VarChar),
|
||||||
BTRIM(String("btrim")),
|
BTRIM(Char()("btrim")),
|
||||||
BTRIM(AllTypes.VarChar, String("AA")),
|
BTRIM(AllTypes.VarChar, String("AA")),
|
||||||
BTRIM(String("btrim"), String("AA")),
|
BTRIM(VarChar(11)("btrim"), String("AA")),
|
||||||
LTRIM(AllTypes.VarChar),
|
LTRIM(AllTypes.VarChar),
|
||||||
LTRIM(String("ltrim")),
|
LTRIM(String("ltrim")),
|
||||||
LTRIM(AllTypes.VarChar, String("A")),
|
LTRIM(AllTypes.VarChar, String("A")),
|
||||||
|
|
@ -533,7 +533,7 @@ func TestStringOperators(t *testing.T) {
|
||||||
TO_HEX(AllTypes.IntegerPtr),
|
TO_HEX(AllTypes.IntegerPtr),
|
||||||
)
|
)
|
||||||
|
|
||||||
dest := []struct{}{}
|
var dest []struct{}
|
||||||
err := query.Query(db, &dest)
|
err := query.Query(db, &dest)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
@ -630,9 +630,9 @@ func TestFloatOperators(t *testing.T) {
|
||||||
AllTypes.Numeric.BETWEEN(Float(1.34), AllTypes.Decimal).AS("between"),
|
AllTypes.Numeric.BETWEEN(Float(1.34), AllTypes.Decimal).AS("between"),
|
||||||
AllTypes.Numeric.NOT_BETWEEN(AllTypes.Decimal.MUL(Float(3)), Float(100.12)).AS("not_between"),
|
AllTypes.Numeric.NOT_BETWEEN(AllTypes.Decimal.MUL(Float(3)), Float(100.12)).AS("not_between"),
|
||||||
|
|
||||||
TRUNC(AllTypes.Decimal.ADD(AllTypes.Decimal), Uint8(2)).AS("add1"),
|
TRUNC(AllTypes.Decimal.ADD(AllTypes.Decimal), Int8(2)).AS("add1"),
|
||||||
TRUNC(AllTypes.Decimal.ADD(Float(11.22)), Int8(2)).AS("add2"),
|
TRUNC(AllTypes.Decimal.ADD(Float(11.22)), Int8(2)).AS("add2"),
|
||||||
TRUNC(AllTypes.Decimal.SUB(AllTypes.DecimalPtr), Uint16(2)).AS("sub1"),
|
TRUNC(AllTypes.Decimal.SUB(AllTypes.DecimalPtr), Int32(2)).AS("sub1"),
|
||||||
TRUNC(AllTypes.Decimal.SUB(Float(11.22)), Int16(2)).AS("sub2"),
|
TRUNC(AllTypes.Decimal.SUB(Float(11.22)), Int16(2)).AS("sub2"),
|
||||||
TRUNC(AllTypes.Decimal.MUL(AllTypes.DecimalPtr), Int16(2)).AS("mul1"),
|
TRUNC(AllTypes.Decimal.MUL(AllTypes.DecimalPtr), Int16(2)).AS("mul1"),
|
||||||
TRUNC(AllTypes.Decimal.MUL(Float(11.22)), Int32(2)).AS("mul2"),
|
TRUNC(AllTypes.Decimal.MUL(Float(11.22)), Int32(2)).AS("mul2"),
|
||||||
|
|
@ -736,13 +736,13 @@ func TestIntegerOperators(t *testing.T) {
|
||||||
AllTypes.Integer.BETWEEN(Int(11), Int(200)).AS("between"),
|
AllTypes.Integer.BETWEEN(Int(11), Int(200)).AS("between"),
|
||||||
AllTypes.Integer.NOT_BETWEEN(Int(66), Int(77)).AS("not_between"),
|
AllTypes.Integer.NOT_BETWEEN(Int(66), Int(77)).AS("not_between"),
|
||||||
AllTypes.BigInt.LT(AllTypes.BigIntPtr).AS("lt1"),
|
AllTypes.BigInt.LT(AllTypes.BigIntPtr).AS("lt1"),
|
||||||
AllTypes.BigInt.LT(Uint8(65)).AS("lt2"),
|
AllTypes.BigInt.LT(Int16(65)).AS("lt2"),
|
||||||
AllTypes.BigInt.LT_EQ(AllTypes.BigIntPtr).AS("lte1"),
|
AllTypes.BigInt.LT_EQ(AllTypes.BigIntPtr).AS("lte1"),
|
||||||
AllTypes.BigInt.LT_EQ(Uint16(65)).AS("lte2"),
|
AllTypes.BigInt.LT_EQ(Int32(65)).AS("lte2"),
|
||||||
AllTypes.BigInt.GT(AllTypes.BigIntPtr).AS("gt1"),
|
AllTypes.BigInt.GT(AllTypes.BigIntPtr).AS("gt1"),
|
||||||
AllTypes.BigInt.GT(Uint32(65)).AS("gt2"),
|
AllTypes.BigInt.GT(Int64(65)).AS("gt2"),
|
||||||
AllTypes.BigInt.GT_EQ(AllTypes.BigIntPtr).AS("gte1"),
|
AllTypes.BigInt.GT_EQ(AllTypes.BigIntPtr).AS("gte1"),
|
||||||
AllTypes.BigInt.GT_EQ(Uint64(65)).AS("gte2"),
|
AllTypes.BigInt.GT_EQ(Int64(65)).AS("gte2"),
|
||||||
|
|
||||||
AllTypes.BigInt.ADD(AllTypes.BigInt).AS("add1"),
|
AllTypes.BigInt.ADD(AllTypes.BigInt).AS("add1"),
|
||||||
AllTypes.BigInt.ADD(Int(11)).AS("add2"),
|
AllTypes.BigInt.ADD(Int(11)).AS("add2"),
|
||||||
|
|
@ -1111,8 +1111,8 @@ func TestRowExpression(t *testing.T) {
|
||||||
nowAddHour := time.Now().Add(time.Hour)
|
nowAddHour := time.Now().Add(time.Hour)
|
||||||
|
|
||||||
stmt := SELECT(
|
stmt := SELECT(
|
||||||
ROW(Int32(1), Float32(11.22), String("john")).AS("row"),
|
ROW(Int32(1), Real(11.22), Text("john")).AS("row"),
|
||||||
WRAP(Int64(1), Float64(11.22), String("john")).AS("wrap"),
|
WRAP(Int64(1), Double(11.22), VarChar(10)("john")).AS("wrap"),
|
||||||
|
|
||||||
ROW(Bool(false), DateT(now)).EQ(ROW(Bool(true), DateT(now))),
|
ROW(Bool(false), DateT(now)).EQ(ROW(Bool(true), DateT(now))),
|
||||||
WRAP(Bool(false), DateT(now)).NOT_EQ(WRAP(Bool(true), DateT(now))),
|
WRAP(Bool(false), DateT(now)).NOT_EQ(WRAP(Bool(true), DateT(now))),
|
||||||
|
|
@ -1131,7 +1131,7 @@ func TestRowExpression(t *testing.T) {
|
||||||
|
|
||||||
testutils.AssertStatementSql(t, stmt, `
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
SELECT ROW($1::integer, $2::real, $3::text) AS "row",
|
SELECT ROW($1::integer, $2::real, $3::text) AS "row",
|
||||||
($4::bigint, $5::double precision, $6::text) AS "wrap",
|
($4::bigint, $5::double precision, $6::varchar(10)) AS "wrap",
|
||||||
ROW($7::boolean, $8::date) = ROW($9::boolean, $10::date),
|
ROW($7::boolean, $8::date) = ROW($9::boolean, $10::date),
|
||||||
($11::boolean, $12::date) != ($13::boolean, $14::date),
|
($11::boolean, $12::date) != ($13::boolean, $14::date),
|
||||||
ROW($15::time without time zone) IS DISTINCT FROM (row(NOW()::time)),
|
ROW($15::time without time zone) IS DISTINCT FROM (row(NOW()::time)),
|
||||||
|
|
|
||||||
|
|
@ -660,8 +660,8 @@ func TestSelectExecution1(t *testing.T) {
|
||||||
).
|
).
|
||||||
WHERE(
|
WHERE(
|
||||||
OR(
|
OR(
|
||||||
City.City.EQ(String("London")),
|
City.City.EQ(Text("London")),
|
||||||
City.City.EQ(String("York")),
|
City.City.EQ(Text("York")),
|
||||||
),
|
),
|
||||||
).
|
).
|
||||||
ORDER_BY(
|
ORDER_BY(
|
||||||
|
|
@ -741,7 +741,7 @@ func TestSelectExecution2(t *testing.T) {
|
||||||
Customer.CustomerID.AS("my_customer.id"),
|
Customer.CustomerID.AS("my_customer.id"),
|
||||||
Customer.LastName.AS("my_customer.last_name"),
|
Customer.LastName.AS("my_customer.last_name"),
|
||||||
).
|
).
|
||||||
WHERE(City.City.EQ(String("London")).OR(City.City.EQ(String("York")))).
|
WHERE(City.City.EQ(VarChar()("London")).OR(City.City.EQ(VarChar()("York")))).
|
||||||
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
|
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, stmt, `
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
|
@ -754,7 +754,7 @@ SELECT city.city_id AS "my_city.id",
|
||||||
FROM dvds.city
|
FROM dvds.city
|
||||||
INNER JOIN dvds.address ON (address.city_id = city.city_id)
|
INNER JOIN dvds.address ON (address.city_id = city.city_id)
|
||||||
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
|
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
|
||||||
WHERE (city.city = 'London'::text) OR (city.city = 'York'::text)
|
WHERE (city.city = 'London'::varchar) OR (city.city = 'York'::varchar)
|
||||||
ORDER BY city.city_id, address.address_id, customer.customer_id;
|
ORDER BY city.city_id, address.address_id, customer.customer_id;
|
||||||
`, "London", "York")
|
`, "London", "York")
|
||||||
|
|
||||||
|
|
@ -798,7 +798,7 @@ func TestSelectExecution3(t *testing.T) {
|
||||||
Address.AddressID.AS("address_id"),
|
Address.AddressID.AS("address_id"),
|
||||||
Address.Address.AS("address_line"),
|
Address.Address.AS("address_line"),
|
||||||
).
|
).
|
||||||
WHERE(City.City.EQ(String("London")).OR(City.City.EQ(String("York")))).
|
WHERE(City.City.EQ(VarChar(20)("London")).OR(City.City.EQ(VarChar(20)("York")))).
|
||||||
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
|
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, stmt, `
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
|
@ -811,7 +811,7 @@ SELECT city.city_id AS "city_id",
|
||||||
FROM dvds.city
|
FROM dvds.city
|
||||||
INNER JOIN dvds.address ON (address.city_id = city.city_id)
|
INNER JOIN dvds.address ON (address.city_id = city.city_id)
|
||||||
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
|
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
|
||||||
WHERE (city.city = 'London'::text) OR (city.city = 'York'::text)
|
WHERE (city.city = 'London'::varchar(20)) OR (city.city = 'York'::varchar(20))
|
||||||
ORDER BY city.city_id, address.address_id, customer.customer_id;
|
ORDER BY city.city_id, address.address_id, customer.customer_id;
|
||||||
`, "London", "York")
|
`, "London", "York")
|
||||||
|
|
||||||
|
|
@ -1866,7 +1866,7 @@ SELECT customer.customer_id AS "customer.customer_id",
|
||||||
FROM dvds.payment
|
FROM dvds.payment
|
||||||
INNER JOIN dvds.customer ON (customer.customer_id = payment.customer_id)
|
INNER JOIN dvds.customer ON (customer.customer_id = payment.customer_id)
|
||||||
GROUP BY customer.customer_id
|
GROUP BY customer.customer_id
|
||||||
HAVING SUM(payment.amount) > 125.6
|
HAVING SUM(payment.amount) > 125::real
|
||||||
ORDER BY customer.customer_id, SUM(payment.amount) ASC;
|
ORDER BY customer.customer_id, SUM(payment.amount) ASC;
|
||||||
`
|
`
|
||||||
query := SELECT(
|
query := SELECT(
|
||||||
|
|
@ -1885,14 +1885,14 @@ ORDER BY customer.customer_id, SUM(payment.amount) ASC;
|
||||||
).GROUP_BY(
|
).GROUP_BY(
|
||||||
Customer.CustomerID,
|
Customer.CustomerID,
|
||||||
).HAVING(
|
).HAVING(
|
||||||
SUMf(Payment.Amount).GT(Float(125.6)),
|
SUMf(Payment.Amount).GT(Real(125)),
|
||||||
).ORDER_BY(
|
).ORDER_BY(
|
||||||
Customer.CustomerID, SUMf(Payment.Amount).ASC(),
|
Customer.CustomerID, SUMf(Payment.Amount).ASC(),
|
||||||
)
|
)
|
||||||
|
|
||||||
//fmt.Println(query.DebugSql())
|
//fmt.Println(query.DebugSql())
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, float64(125.6))
|
testutils.AssertDebugStatementSql(t, query, expectedSQL, float32(125))
|
||||||
|
|
||||||
var dest []struct {
|
var dest []struct {
|
||||||
model.Customer
|
model.Customer
|
||||||
|
|
@ -2378,14 +2378,14 @@ func TestSelectUnion(t *testing.T) {
|
||||||
SELECT payment.payment_id AS "payment.payment_id",
|
SELECT payment.payment_id AS "payment.payment_id",
|
||||||
payment.amount AS "payment.amount"
|
payment.amount AS "payment.amount"
|
||||||
FROM dvds.payment
|
FROM dvds.payment
|
||||||
WHERE payment.amount <= 100
|
WHERE payment.amount <= 100::double precision
|
||||||
)
|
)
|
||||||
UNION ALL
|
UNION ALL
|
||||||
(
|
(
|
||||||
SELECT payment.payment_id AS "payment.payment_id",
|
SELECT payment.payment_id AS "payment.payment_id",
|
||||||
payment.amount AS "payment.amount"
|
payment.amount AS "payment.amount"
|
||||||
FROM dvds.payment
|
FROM dvds.payment
|
||||||
WHERE payment.amount >= 200
|
WHERE payment.amount >= 200::double precision
|
||||||
)
|
)
|
||||||
ORDER BY "payment.payment_id" ASC, "payment.amount" DESC
|
ORDER BY "payment.payment_id" ASC, "payment.amount" DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
|
|
@ -2394,10 +2394,10 @@ OFFSET 20;
|
||||||
query := UNION_ALL(
|
query := UNION_ALL(
|
||||||
Payment.
|
Payment.
|
||||||
SELECT(Payment.PaymentID.AS("payment.payment_id"), Payment.Amount).
|
SELECT(Payment.PaymentID.AS("payment.payment_id"), Payment.Amount).
|
||||||
WHERE(Payment.Amount.LT_EQ(Float(100))),
|
WHERE(Payment.Amount.LT_EQ(Double(100))),
|
||||||
Payment.
|
Payment.
|
||||||
SELECT(Payment.PaymentID, Payment.Amount).
|
SELECT(Payment.PaymentID, Payment.Amount).
|
||||||
WHERE(Payment.Amount.GT_EQ(Float(200))),
|
WHERE(Payment.Amount.GT_EQ(Double(200))),
|
||||||
).ORDER_BY(
|
).ORDER_BY(
|
||||||
IntegerColumn("payment.payment_id").ASC(),
|
IntegerColumn("payment.payment_id").ASC(),
|
||||||
Payment.Amount.DESC(),
|
Payment.Amount.DESC(),
|
||||||
|
|
@ -2729,7 +2729,7 @@ FROM dvds.actor
|
||||||
INNER JOIN dvds.language ON (language.language_id = film.language_id)
|
INNER JOIN dvds.language ON (language.language_id = film.language_id)
|
||||||
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
|
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
|
||||||
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
|
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
|
||||||
WHERE ((language.name = 'English'::text) AND (category.name != 'Action'::text)) AND (film.length > 180)
|
WHERE ((language.name = 'English'::char(20)) AND (category.name != 'Action'::text)) AND (film.length > 180::integer)
|
||||||
ORDER BY actor.actor_id ASC, film.film_id ASC;
|
ORDER BY actor.actor_id ASC, film.film_id ASC;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -2746,15 +2746,15 @@ ORDER BY actor.actor_id ASC, film.film_id ASC;
|
||||||
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
|
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
|
||||||
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
|
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
|
||||||
).WHERE(
|
).WHERE(
|
||||||
Language.Name.EQ(String("English")). // note that every column has type.
|
Language.Name.EQ(Char(20)("English")). // note that every column has type.
|
||||||
AND(Category.Name.NOT_EQ(String("Action"))). // String column Language.Name and Category.Name can be compared only with string expression
|
AND(Category.Name.NOT_EQ(Text("Action"))). // String column Language.Name and Category.Name can be compared only with string expression
|
||||||
AND(Film.Length.GT(Int(180))), // Film.Length is integer column and can be compared only with integer expression
|
AND(Film.Length.GT(Int32(180))), // Film.Length is integer column and can be compared only with integer expression
|
||||||
).ORDER_BY(
|
).ORDER_BY(
|
||||||
Actor.ActorID.ASC(),
|
Actor.ActorID.ASC(),
|
||||||
Film.FilmID.ASC(),
|
Film.FilmID.ASC(),
|
||||||
)
|
)
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "English", "Action", int64(180))
|
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "English", "Action", int32(180))
|
||||||
|
|
||||||
var dest []struct {
|
var dest []struct {
|
||||||
model.Actor
|
model.Actor
|
||||||
|
|
@ -3162,7 +3162,7 @@ func TestSelectLateral(t *testing.T) {
|
||||||
).FROM(
|
).FROM(
|
||||||
Language,
|
Language,
|
||||||
).WHERE(
|
).WHERE(
|
||||||
Language.Name.NOT_IN(String("spanish")).
|
Language.Name.NOT_IN(Char(20)("Spanish"), Char(20)("Catalan")).
|
||||||
AND(Film.LanguageID.EQ(Language.LanguageID)),
|
AND(Film.LanguageID.EQ(Language.LanguageID)),
|
||||||
),
|
),
|
||||||
).AS("films")
|
).AS("films")
|
||||||
|
|
@ -3191,7 +3191,7 @@ FROM dvds.film
|
||||||
language.name AS "language.name",
|
language.name AS "language.name",
|
||||||
language.last_update AS "language.last_update"
|
language.last_update AS "language.last_update"
|
||||||
FROM dvds.language
|
FROM dvds.language
|
||||||
WHERE (language.name NOT IN ('spanish'::text)) AND (film.language_id = language.language_id)
|
WHERE (language.name NOT IN ('Spanish'::char(20), 'Catalan'::char(20))) AND (film.language_id = language.language_id)
|
||||||
) AS films
|
) AS films
|
||||||
WHERE film.film_id = 1
|
WHERE film.film_id = 1
|
||||||
ORDER BY film.film_id
|
ORDER BY film.film_id
|
||||||
|
|
@ -3236,7 +3236,7 @@ FROM dvds.film,
|
||||||
language.name AS "language.name",
|
language.name AS "language.name",
|
||||||
language.last_update AS "language.last_update"
|
language.last_update AS "language.last_update"
|
||||||
FROM dvds.language
|
FROM dvds.language
|
||||||
WHERE (language.name NOT IN ('spanish'::text)) AND (film.language_id = language.language_id)
|
WHERE (language.name NOT IN ('Spanish'::char(20), 'Catalan'::char(20))) AND (film.language_id = language.language_id)
|
||||||
) AS films
|
) AS films
|
||||||
WHERE film.film_id = 1
|
WHERE film.film_id = 1
|
||||||
ORDER BY film.film_id
|
ORDER BY film.film_id
|
||||||
|
|
@ -3787,9 +3787,9 @@ func TestSelectConditionalFunctions(t *testing.T) {
|
||||||
Film.SELECT(Film.FilmID).WHERE(Film.RentalDuration.GT(Int(100))),
|
Film.SELECT(Film.FilmID).WHERE(Film.RentalDuration.GT(Int(100))),
|
||||||
).AS("exists"),
|
).AS("exists"),
|
||||||
CASE(Film.Length.GT(Int(120))).
|
CASE(Film.Length.GT(Int(120))).
|
||||||
WHEN(Bool(true)).THEN(String("long film")).
|
WHEN(Bool(true)).THEN(Text("long film")).
|
||||||
ELSE(String("short film")).AS("case"),
|
ELSE(Text("short film")).AS("case"),
|
||||||
COALESCE(Film.Description, String("none")).AS("coalesce"),
|
COALESCE(Film.Description, Text("none")).AS("coalesce"),
|
||||||
NULLIF(Film.ReleaseYear, Int(200)).AS("null_if"),
|
NULLIF(Film.ReleaseYear, Int(200)).AS("null_if"),
|
||||||
GREATEST(Film.RentalDuration, Int(4), Int(5)).AS("greatest"),
|
GREATEST(Film.RentalDuration, Int(4), Int(5)).AS("greatest"),
|
||||||
LEAST(Film.RentalDuration, Int(7), Int(6)).AS("least"),
|
LEAST(Film.RentalDuration, Int(7), Int(6)).AS("least"),
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ import (
|
||||||
func TestVALUES(t *testing.T) {
|
func TestVALUES(t *testing.T) {
|
||||||
|
|
||||||
values := VALUES(
|
values := VALUES(
|
||||||
WRAP(Int32(1), Int32(2), Float32(4.666), Bool(false), String("txt")),
|
WRAP(Int32(1), Int32(2), Real(4.666), Bool(false), String("txt")),
|
||||||
WRAP(Int32(11).ADD(Int32(2)), Int32(22), Float32(33.222), Bool(true), String("png")),
|
WRAP(Int32(11).ADD(Int32(2)), Int32(22), Real(33.222), Bool(true), String("png")),
|
||||||
WRAP(Int32(11), Int32(22), Float32(33.222), Bool(true), NULL),
|
WRAP(Int32(11), Int32(22), Real(33.222), Bool(true), NULL),
|
||||||
).AS("values_table")
|
).AS("values_table")
|
||||||
|
|
||||||
stmt := SELECT(
|
stmt := SELECT(
|
||||||
|
|
@ -86,11 +86,11 @@ func TestVALUES_Join(t *testing.T) {
|
||||||
lastUpdate := Timestamp(2007, time.February, 11, 12, 0, 0)
|
lastUpdate := Timestamp(2007, time.February, 11, 12, 0, 0)
|
||||||
|
|
||||||
filmValues := VALUES(
|
filmValues := VALUES(
|
||||||
WRAP(String("Chamber Italian"), Int64(117), Int32(2005), Float32(5.82), lastUpdate),
|
WRAP(String("Chamber Italian"), Int64(117), Int32(2005), Real(5.82), lastUpdate),
|
||||||
WRAP(String("Grosse Wonderful"), Int64(49), Int32(2004), Float32(6.242), lastUpdate.ADD(INTERVAL(1, HOUR))),
|
WRAP(String("Grosse Wonderful"), Int64(49), Int32(2004), Real(6.242), lastUpdate.ADD(INTERVAL(1, HOUR))),
|
||||||
WRAP(String("Airport Pollock"), Int64(54), Int32(2001), Float32(7.22), NULL),
|
WRAP(String("Airport Pollock"), Int64(54), Int32(2001), Real(7.22), NULL),
|
||||||
WRAP(String("Bright Encounters"), Int64(73), Int32(2002), Float32(8.25), NULL),
|
WRAP(String("Bright Encounters"), Int64(73), Int32(2002), Real(8.25), NULL),
|
||||||
WRAP(String("Academy Dinosaur"), Int64(83), Int32(2010), Float32(9.22), lastUpdate.SUB(INTERVAL(2, MINUTE))),
|
WRAP(String("Academy Dinosaur"), Int64(83), Int32(2010), Real(9.22), lastUpdate.SUB(INTERVAL(2, MINUTE))),
|
||||||
).AS("film_values",
|
).AS("film_values",
|
||||||
title, IntegerColumn("length"), releaseYear, rentalRate, TimestampColumn("update_date"))
|
title, IntegerColumn("length"), releaseYear, rentalRate, TimestampColumn("update_date"))
|
||||||
|
|
||||||
|
|
@ -216,10 +216,10 @@ func TestVALUES_CTE_Update(t *testing.T) {
|
||||||
stmt := WITH(
|
stmt := WITH(
|
||||||
paymentsToUpdate.AS(
|
paymentsToUpdate.AS(
|
||||||
VALUES(
|
VALUES(
|
||||||
WRAP(Int32(20564), Float32(1.21)),
|
WRAP(Int32(20564), Real(1.21)),
|
||||||
WRAP(Int32(20567), Float32(1.02)),
|
WRAP(Int32(20567), Real(1.02)),
|
||||||
WRAP(Int32(20570), Float32(1.34)),
|
WRAP(Int32(20570), Real(1.34)),
|
||||||
WRAP(Int32(20573), Float32(1.72)),
|
WRAP(Int32(20573), Real(1.72)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)(
|
)(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue