Merge pull request #78 from go-jet/develop

Merge develop to master for 2.5.0 release
This commit is contained in:
go-jet 2021-05-21 17:20:27 +02:00 committed by GitHub
commit f0bf2c36b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
80 changed files with 2905 additions and 461 deletions

View file

@ -6,7 +6,7 @@ jobs:
build-postgres-and-mysql:
docker:
# specify the version
- image: circleci/golang:1.11
- image: circleci/golang:1.13
- image: circleci/postgres:10.8-alpine
environment: # environment variables for primary container
@ -14,7 +14,7 @@ jobs:
POSTGRES_PASSWORD: jet
POSTGRES_DB: jetdb
- image: circleci/mysql:8.0
- image: circleci/mysql:8.0.16
command: [--default-authentication-plugin=mysql_native_password]
environment:
MYSQL_ROOT_PASSWORD: jet
@ -41,17 +41,9 @@ jobs:
- run:
name: Install dependencies
command: |
go get github.com/google/uuid
go get github.com/lib/pq
go get github.com/go-sql-driver/mysql
go get github.com/pkg/profile
go get github.com/stretchr/testify/assert
go get github.com/google/go-cmp/cmp
go get github.com/davecgh/go-spew/spew
cd /go/src/github.com/go-jet/jet
go get github.com/jstemmer/go-junit-report
go install github.com/go-jet/jet/cmd/jet
go build -o /home/circleci/.local/bin/jet ./cmd/jet/
- run:
name: Waiting for Postgres to be ready
@ -85,6 +77,7 @@ jobs:
mysql -h 127.0.0.1 -u root -pjet -e "grant all privileges on *.* to 'jet'@'%';"
mysql -h 127.0.0.1 -u root -pjet -e "set global sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';"
mysql -h 127.0.0.1 -u jet -pjet -e "create database test_sample"
mysql -h 127.0.0.1 -u jet -pjet -e "create database dvds2"
- run:
name: Init Postgres database
@ -95,7 +88,7 @@ jobs:
- run: mkdir -p $TEST_RESULTS
- run: go test -v ./... -coverpkg=github.com/go-jet/jet/postgres/...,github.com/go-jet/jet/mysql/...,github.com/go-jet/jet/qrm/...,github.com/go-jet/jet/generator/...,github.com/go-jet/jet/internal/... -coverprofile=cover.out 2>&1 | go-junit-report > $TEST_RESULTS/results.xml
- run: MY_SQL_SOURCE=MySQL go test -v ./... -coverpkg=github.com/go-jet/jet/postgres/...,github.com/go-jet/jet/mysql/...,github.com/go-jet/jet/qrm/...,github.com/go-jet/jet/generator/...,github.com/go-jet/jet/internal/... -coverprofile=cover.out 2>&1 | go-junit-report > $TEST_RESULTS/results.xml
- run:
name: Upload code coverage
@ -110,7 +103,7 @@ jobs:
build-mariadb:
docker:
# specify the version
- image: circleci/golang:1.11
- image: circleci/golang:1.13
- image: circleci/mariadb:10.3
command: [--default-authentication-plugin=mysql_native_password]
@ -138,17 +131,9 @@ jobs:
- run:
name: Install dependencies
command: |
go get github.com/google/uuid
go get github.com/lib/pq
go get github.com/go-sql-driver/mysql
go get github.com/pkg/profile
go get github.com/stretchr/testify/assert
go get github.com/google/go-cmp/cmp
go get github.com/davecgh/go-spew/spew
cd /go/src/github.com/go-jet/jet
go get github.com/jstemmer/go-junit-report
go install github.com/go-jet/jet/cmd/jet
go build -o /home/circleci/.local/bin/jet ./cmd/jet/
- run:
name: Install MySQL CLI;
@ -161,6 +146,7 @@ jobs:
mysql -h 127.0.0.1 -u root -pjet -e "grant all privileges on *.* to 'jet'@'%';"
mysql -h 127.0.0.1 -u root -pjet -e "set global sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';"
mysql -h 127.0.0.1 -u jet -pjet -e "create database test_sample"
mysql -h 127.0.0.1 -u jet -pjet -e "create database dvds2"
- run:
name: Init MariaDB database
@ -172,7 +158,7 @@ jobs:
- run:
name: Run MariaDB tests
command: |
go test -v ./tests/mysql/ -source=MariaDB
MY_SQL_SOURCE=MariaDB go test -v ./tests/mysql/
workflows:
version: 2

View file

@ -62,24 +62,33 @@ To install Jet package, you need to install Go and set your Go workspace first.
### Installation
Use the bellow command to add jet as a dependency into `go.mod` project:
Use the command bellow to add jet as a dependency into `go.mod` project:
```sh
$ go get -u github.com/go-jet/jet/v2
```
Use the bellow command to add jet as a dependency into `GOPATH` project:
```sh
$ go get -u github.com/go-jet/jet
```
Install jet generator to GOPATH bin folder. This will allow generating jet files from the command line.
Jet generator can be install in the following ways:
1) Install jet generator to GOPATH/bin folder:
```sh
cd $GOPATH/src/ && GO111MODULE=off go get -u github.com/go-jet/jet/cmd/jet
```
*Make sure GOPATH/bin folder is added to the PATH environment variable.*
*Make sure GOPATH bin folder is added to the PATH environment variable.*
2) Install jet generator to specific folder:
```sh
git clone https://github.com/go-jet/jet.git
cd jet && go build -o dir_path ./cmd/jet
```
*Make sure `dir_path` folder is added to the PATH environment variable.*
3) (Go1.16+) Install jet generator using go install:
```sh
go install github.com/go-jet/jet/v2/cmd/jet@latest
```
*Jet generator is installed to the directory named by the GOBIN environment variable,
which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH environment variable is not set.*
### Quick Start
For this quick start example we will use PostgreSQL sample _'dvd rental'_ database. Full database dump can be found in [./tests/testdata/init/postgres/dvds.sql](./tests/testdata/init/postgres/dvds.sql).
@ -519,26 +528,17 @@ The biggest benefit is speed. Speed is improved in 3 major areas:
##### Speed of development
Writing SQL queries is faster and easier, because the developers have help of SQL code completion and SQL type safety directly from Go.
Writing SQL queries is faster and easier as the developers have help of SQL code completion and SQL type safety directly from Go.
Automatic scan to arbitrary structure removes a lot of headache and boilerplate code needed to structure database query result.
##### Speed of execution
While ORM libraries can introduce significant performance penalties due to number of round-trips to the database,
Jet will always perform much better, because of the single database call.
Jet will always perform better as developers can write complex query and retrieve result with a single database call.
Thus handler time lost on latency between server and database can be constant. Handler execution will be proportional
only to the query complexity and the number of rows returned from database.
Common web and database server usually are not on the same physical machine, and there is some latency between them.
Latency can vary from 5ms to 50+ms. In majority of cases query executed on database is simple query lasting no more than 1ms.
In those cases web server handler execution time is directly proportional to latency between server and database.
This is not such a big problem if handler calls database couple of times, but what if web server is using ORM to retrieve data from database.
ORM sometimes can access the database once for every object needed. Now lets say latency is 30ms and there are 100
different objects required from the database. This handler will last 3 seconds !!!.
With Jet, handler time lost on latency between server and database is constant. Because we can write complex query and
return result in one database call. Handler execution will be only proportional to the number of rows returned from database.
ORM example replaced with jet will take just 30ms + 'result scan time' = 31ms (rough estimate).
With Jet you can even join the whole database and store the whole structured result in one database call.
With Jet it is even possible to join the whole database and store the whole structured result in one database call.
This is exactly what is being done in one of the tests: [TestJoinEverything](/tests/postgres/chinook_db_test.go#L40).
The whole test database is joined and query result(~10,000 rows) is stored in a structured variable in less than 0.7s.
@ -570,6 +570,7 @@ To run the tests, additional dependencies are required:
- `github.com/pkg/profile`
- `github.com/stretchr/testify`
- `github.com/google/go-cmp`
- `github.com/jackc/pgx/v4`
## Versioning
@ -577,5 +578,5 @@ To run the tests, additional dependencies are required:
## License
Copyright 2019-2020 Goran Bjelanovic
Copyright 2019-2021 Goran Bjelanovic
Licensed under the Apache License, Version 2.0.

View file

@ -47,7 +47,7 @@ func main() {
flag.Usage = func() {
_, _ = fmt.Fprint(os.Stdout, `
Jet generator 2.3.0
Jet generator 2.5.0
Usage:
-source string

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var Actor = newActorTable()
var Actor = newActorTable("dvds", "actor", "")
type actorTable struct {
postgres.Table
@ -33,20 +33,23 @@ type ActorTable struct {
}
// AS creates new ActorTable with assigned alias
func (a *ActorTable) AS(alias string) *ActorTable {
aliasTable := newActorTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a ActorTable) AS(alias string) *ActorTable {
return newActorTable(a.SchemaName(), a.TableName(), alias)
}
func newActorTable() *ActorTable {
// Schema creates new ActorTable with assigned schema name
func (a ActorTable) FromSchema(schemaName string) *ActorTable {
return newActorTable(schemaName, a.TableName(), a.Alias())
}
func newActorTable(schemaName, tableName, alias string) *ActorTable {
return &ActorTable{
actorTable: newActorTableImpl("dvds", "actor"),
EXCLUDED: newActorTableImpl("", "excluded"),
actorTable: newActorTableImpl(schemaName, tableName, alias),
EXCLUDED: newActorTableImpl("", "excluded", ""),
}
}
func newActorTableImpl(schemaName, tableName string) actorTable {
func newActorTableImpl(schemaName, tableName, alias string) actorTable {
var (
ActorIDColumn = postgres.IntegerColumn("actor_id")
FirstNameColumn = postgres.StringColumn("first_name")
@ -57,7 +60,7 @@ func newActorTableImpl(schemaName, tableName string) actorTable {
)
return actorTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var Category = newCategoryTable()
var Category = newCategoryTable("dvds", "category", "")
type categoryTable struct {
postgres.Table
@ -32,20 +32,23 @@ type CategoryTable struct {
}
// AS creates new CategoryTable with assigned alias
func (a *CategoryTable) AS(alias string) *CategoryTable {
aliasTable := newCategoryTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a CategoryTable) AS(alias string) *CategoryTable {
return newCategoryTable(a.SchemaName(), a.TableName(), alias)
}
func newCategoryTable() *CategoryTable {
// Schema creates new CategoryTable with assigned schema name
func (a CategoryTable) FromSchema(schemaName string) *CategoryTable {
return newCategoryTable(schemaName, a.TableName(), a.Alias())
}
func newCategoryTable(schemaName, tableName, alias string) *CategoryTable {
return &CategoryTable{
categoryTable: newCategoryTableImpl("dvds", "category"),
EXCLUDED: newCategoryTableImpl("", "excluded"),
categoryTable: newCategoryTableImpl(schemaName, tableName, alias),
EXCLUDED: newCategoryTableImpl("", "excluded", ""),
}
}
func newCategoryTableImpl(schemaName, tableName string) categoryTable {
func newCategoryTableImpl(schemaName, tableName, alias string) categoryTable {
var (
CategoryIDColumn = postgres.IntegerColumn("category_id")
NameColumn = postgres.StringColumn("name")
@ -55,7 +58,7 @@ func newCategoryTableImpl(schemaName, tableName string) categoryTable {
)
return categoryTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
CategoryID: CategoryIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var Film = newFilmTable()
var Film = newFilmTable("dvds", "film", "")
type filmTable struct {
postgres.Table
@ -42,20 +42,23 @@ type FilmTable struct {
}
// AS creates new FilmTable with assigned alias
func (a *FilmTable) AS(alias string) *FilmTable {
aliasTable := newFilmTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a FilmTable) AS(alias string) *FilmTable {
return newFilmTable(a.SchemaName(), a.TableName(), alias)
}
func newFilmTable() *FilmTable {
// Schema creates new FilmTable with assigned schema name
func (a FilmTable) FromSchema(schemaName string) *FilmTable {
return newFilmTable(schemaName, a.TableName(), a.Alias())
}
func newFilmTable(schemaName, tableName, alias string) *FilmTable {
return &FilmTable{
filmTable: newFilmTableImpl("dvds", "film"),
EXCLUDED: newFilmTableImpl("", "excluded"),
filmTable: newFilmTableImpl(schemaName, tableName, alias),
EXCLUDED: newFilmTableImpl("", "excluded", ""),
}
}
func newFilmTableImpl(schemaName, tableName string) filmTable {
func newFilmTableImpl(schemaName, tableName, alias string) filmTable {
var (
FilmIDColumn = postgres.IntegerColumn("film_id")
TitleColumn = postgres.StringColumn("title")
@ -75,7 +78,7 @@ func newFilmTableImpl(schemaName, tableName string) filmTable {
)
return filmTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
FilmID: FilmIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var FilmActor = newFilmActorTable()
var FilmActor = newFilmActorTable("dvds", "film_actor", "")
type filmActorTable struct {
postgres.Table
@ -32,20 +32,23 @@ type FilmActorTable struct {
}
// AS creates new FilmActorTable with assigned alias
func (a *FilmActorTable) AS(alias string) *FilmActorTable {
aliasTable := newFilmActorTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a FilmActorTable) AS(alias string) *FilmActorTable {
return newFilmActorTable(a.SchemaName(), a.TableName(), alias)
}
func newFilmActorTable() *FilmActorTable {
// Schema creates new FilmActorTable with assigned schema name
func (a FilmActorTable) FromSchema(schemaName string) *FilmActorTable {
return newFilmActorTable(schemaName, a.TableName(), a.Alias())
}
func newFilmActorTable(schemaName, tableName, alias string) *FilmActorTable {
return &FilmActorTable{
filmActorTable: newFilmActorTableImpl("dvds", "film_actor"),
EXCLUDED: newFilmActorTableImpl("", "excluded"),
filmActorTable: newFilmActorTableImpl(schemaName, tableName, alias),
EXCLUDED: newFilmActorTableImpl("", "excluded", ""),
}
}
func newFilmActorTableImpl(schemaName, tableName string) filmActorTable {
func newFilmActorTableImpl(schemaName, tableName, alias string) filmActorTable {
var (
ActorIDColumn = postgres.IntegerColumn("actor_id")
FilmIDColumn = postgres.IntegerColumn("film_id")
@ -55,7 +58,7 @@ func newFilmActorTableImpl(schemaName, tableName string) filmActorTable {
)
return filmActorTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var FilmCategory = newFilmCategoryTable()
var FilmCategory = newFilmCategoryTable("dvds", "film_category", "")
type filmCategoryTable struct {
postgres.Table
@ -32,20 +32,23 @@ type FilmCategoryTable struct {
}
// AS creates new FilmCategoryTable with assigned alias
func (a *FilmCategoryTable) AS(alias string) *FilmCategoryTable {
aliasTable := newFilmCategoryTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a FilmCategoryTable) AS(alias string) *FilmCategoryTable {
return newFilmCategoryTable(a.SchemaName(), a.TableName(), alias)
}
func newFilmCategoryTable() *FilmCategoryTable {
// Schema creates new FilmCategoryTable with assigned schema name
func (a FilmCategoryTable) FromSchema(schemaName string) *FilmCategoryTable {
return newFilmCategoryTable(schemaName, a.TableName(), a.Alias())
}
func newFilmCategoryTable(schemaName, tableName, alias string) *FilmCategoryTable {
return &FilmCategoryTable{
filmCategoryTable: newFilmCategoryTableImpl("dvds", "film_category"),
EXCLUDED: newFilmCategoryTableImpl("", "excluded"),
filmCategoryTable: newFilmCategoryTableImpl(schemaName, tableName, alias),
EXCLUDED: newFilmCategoryTableImpl("", "excluded", ""),
}
}
func newFilmCategoryTableImpl(schemaName, tableName string) filmCategoryTable {
func newFilmCategoryTableImpl(schemaName, tableName, alias string) filmCategoryTable {
var (
FilmIDColumn = postgres.IntegerColumn("film_id")
CategoryIDColumn = postgres.IntegerColumn("category_id")
@ -55,7 +58,7 @@ func newFilmCategoryTableImpl(schemaName, tableName string) filmCategoryTable {
)
return filmCategoryTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
FilmID: FilmIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var Language = newLanguageTable()
var Language = newLanguageTable("dvds", "language", "")
type languageTable struct {
postgres.Table
@ -32,20 +32,23 @@ type LanguageTable struct {
}
// AS creates new LanguageTable with assigned alias
func (a *LanguageTable) AS(alias string) *LanguageTable {
aliasTable := newLanguageTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a LanguageTable) AS(alias string) *LanguageTable {
return newLanguageTable(a.SchemaName(), a.TableName(), alias)
}
func newLanguageTable() *LanguageTable {
// Schema creates new LanguageTable with assigned schema name
func (a LanguageTable) FromSchema(schemaName string) *LanguageTable {
return newLanguageTable(schemaName, a.TableName(), a.Alias())
}
func newLanguageTable(schemaName, tableName, alias string) *LanguageTable {
return &LanguageTable{
languageTable: newLanguageTableImpl("dvds", "language"),
EXCLUDED: newLanguageTableImpl("", "excluded"),
languageTable: newLanguageTableImpl(schemaName, tableName, alias),
EXCLUDED: newLanguageTableImpl("", "excluded", ""),
}
}
func newLanguageTableImpl(schemaName, tableName string) languageTable {
func newLanguageTableImpl(schemaName, tableName, alias string) languageTable {
var (
LanguageIDColumn = postgres.IntegerColumn("language_id")
NameColumn = postgres.StringColumn("name")
@ -55,7 +58,7 @@ func newLanguageTableImpl(schemaName, tableName string) languageTable {
)
return languageTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
LanguageID: LanguageIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var ActorInfo = newActorInfoTable()
var ActorInfo = newActorInfoTable("dvds", "actor_info", "")
type actorInfoTable struct {
postgres.Table
@ -33,20 +33,23 @@ type ActorInfoTable struct {
}
// AS creates new ActorInfoTable with assigned alias
func (a *ActorInfoTable) AS(alias string) *ActorInfoTable {
aliasTable := newActorInfoTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a ActorInfoTable) AS(alias string) *ActorInfoTable {
return newActorInfoTable(a.SchemaName(), a.TableName(), alias)
}
func newActorInfoTable() *ActorInfoTable {
// Schema creates new ActorInfoTable with assigned schema name
func (a ActorInfoTable) FromSchema(schemaName string) *ActorInfoTable {
return newActorInfoTable(schemaName, a.TableName(), a.Alias())
}
func newActorInfoTable(schemaName, tableName, alias string) *ActorInfoTable {
return &ActorInfoTable{
actorInfoTable: newActorInfoTableImpl("dvds", "actor_info"),
EXCLUDED: newActorInfoTableImpl("", "excluded"),
actorInfoTable: newActorInfoTableImpl(schemaName, tableName, alias),
EXCLUDED: newActorInfoTableImpl("", "excluded", ""),
}
}
func newActorInfoTableImpl(schemaName, tableName string) actorInfoTable {
func newActorInfoTableImpl(schemaName, tableName, alias string) actorInfoTable {
var (
ActorIDColumn = postgres.IntegerColumn("actor_id")
FirstNameColumn = postgres.StringColumn("first_name")
@ -57,7 +60,7 @@ func newActorInfoTableImpl(schemaName, tableName string) actorInfoTable {
)
return actorInfoTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,

View file

@ -11,7 +11,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var CustomerList = newCustomerListTable()
var CustomerList = newCustomerListTable("dvds", "customer_list", "")
type customerListTable struct {
postgres.Table
@ -38,20 +38,23 @@ type CustomerListTable struct {
}
// AS creates new CustomerListTable with assigned alias
func (a *CustomerListTable) AS(alias string) *CustomerListTable {
aliasTable := newCustomerListTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a CustomerListTable) AS(alias string) *CustomerListTable {
return newCustomerListTable(a.SchemaName(), a.TableName(), alias)
}
func newCustomerListTable() *CustomerListTable {
// Schema creates new CustomerListTable with assigned schema name
func (a CustomerListTable) FromSchema(schemaName string) *CustomerListTable {
return newCustomerListTable(schemaName, a.TableName(), a.Alias())
}
func newCustomerListTable(schemaName, tableName, alias string) *CustomerListTable {
return &CustomerListTable{
customerListTable: newCustomerListTableImpl("dvds", "customer_list"),
EXCLUDED: newCustomerListTableImpl("", "excluded"),
customerListTable: newCustomerListTableImpl(schemaName, tableName, alias),
EXCLUDED: newCustomerListTableImpl("", "excluded", ""),
}
}
func newCustomerListTableImpl(schemaName, tableName string) customerListTable {
func newCustomerListTableImpl(schemaName, tableName, alias string) customerListTable {
var (
IDColumn = postgres.IntegerColumn("id")
NameColumn = postgres.StringColumn("name")
@ -67,7 +70,7 @@ func newCustomerListTableImpl(schemaName, tableName string) customerListTable {
)
return customerListTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ID: IDColumn,

View file

@ -4,9 +4,10 @@ import (
"database/sql"
"encoding/json"
"fmt"
_ "github.com/lib/pq"
"io/ioutil"
_ "github.com/lib/pq"
// dot import so that jet go code would resemble as much as native SQL
// dot import is not mandatory
. "github.com/go-jet/jet/v2/examples/quick-start/.gen/jetdb/dvds/table"

View file

@ -23,7 +23,7 @@ import (
"github.com/go-jet/jet/v2/{{dialect.PackageName}}"
)
var {{ToGoIdentifier .Name}} = new{{.GoStructName}}()
var {{ToGoIdentifier .Name}} = new{{.GoStructName}}("{{.SchemaName}}", "{{.Name}}", "")
type {{.GoStructName}} struct {
{{dialect.PackageName}}.Table
@ -38,13 +38,16 @@ type {{.GoStructName}} struct {
}
// AS creates new {{.GoStructName}} with assigned alias
func (a *{{.GoStructName}}) AS(alias string) {{.GoStructName}} {
aliasTable := new{{.GoStructName}}()
aliasTable.Table.AS(alias)
return aliasTable
func (a {{.GoStructName}}) AS(alias string) {{.GoStructName}} {
return new{{.GoStructName}}(a.SchemaName(), a.TableName(), alias)
}
func new{{.GoStructName}}() {{.GoStructName}} {
// Schema creates new {{.GoStructName}} with assigned schema name
func (a {{.GoStructName}}) FromSchema(schemaName string) {{.GoStructName}} {
return new{{.GoStructName}}(schemaName, a.TableName(), a.Alias())
}
func new{{.GoStructName}}(schemaName, tableName, alias string) {{.GoStructName}} {
var (
{{- range .Columns}}
{{ToGoIdentifier .Name}}Column = {{dialect.PackageName}}.{{.SqlBuilderColumnType}}Column("{{.Name}}")
@ -54,7 +57,7 @@ func new{{.GoStructName}}() {{.GoStructName}} {
)
return {{.GoStructName}}{
Table: {{dialect.PackageName}}.NewTable("{{.SchemaName}}", "{{.Name}}", allColumns...),
Table: {{dialect.PackageName}}.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
{{- range .Columns}}
@ -80,7 +83,7 @@ import (
"github.com/go-jet/jet/v2/{{dialect.PackageName}}"
)
var {{ToGoIdentifier .Name}} = new{{.GoStructName}}()
var {{ToGoIdentifier .Name}} = new{{.GoStructName}}("{{.SchemaName}}", "{{.Name}}", "")
type {{.GoStructImplName}} struct {
{{dialect.PackageName}}.Table
@ -101,20 +104,23 @@ type {{.GoStructName}} struct {
}
// AS creates new {{.GoStructName}} with assigned alias
func (a *{{.GoStructName}}) AS(alias string) *{{.GoStructName}} {
aliasTable := new{{.GoStructName}}()
aliasTable.Table.AS(alias)
return aliasTable
func (a {{.GoStructName}}) AS(alias string) *{{.GoStructName}} {
return new{{.GoStructName}}(a.SchemaName(), a.TableName(), alias)
}
func new{{.GoStructName}}() *{{.GoStructName}} {
// Schema creates new {{.GoStructName}} with assigned schema name
func (a {{.GoStructName}}) FromSchema(schemaName string) *{{.GoStructName}} {
return new{{.GoStructName}}(schemaName, a.TableName(), a.Alias())
}
func new{{.GoStructName}}(schemaName, tableName, alias string) *{{.GoStructName}} {
return &{{.GoStructName}}{
{{.GoStructImplName}}: new{{.GoStructName}}Impl("{{.SchemaName}}", "{{.Name}}"),
EXCLUDED: new{{.GoStructName}}Impl("", "excluded"),
{{.GoStructImplName}}: new{{.GoStructName}}Impl(schemaName, tableName, alias),
EXCLUDED: new{{.GoStructName}}Impl("", "excluded", ""),
}
}
func new{{.GoStructName}}Impl(schemaName, tableName string) {{.GoStructImplName}} {
func new{{.GoStructName}}Impl(schemaName, tableName, alias string) {{.GoStructImplName}} {
var (
{{- range .Columns}}
{{ToGoIdentifier .Name}}Column = {{dialect.PackageName}}.{{.SqlBuilderColumnType}}Column("{{.Name}}")
@ -124,7 +130,7 @@ func new{{.GoStructName}}Impl(schemaName, tableName string) {{.GoStructImplName}
)
return {{.GoStructImplName}}{
Table: {{dialect.PackageName}}.NewTable(schemaName, tableName, allColumns...),
Table: {{dialect.PackageName}}.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
{{- range .Columns}}

8
go.mod
View file

@ -4,9 +4,11 @@ go 1.11
require (
github.com/go-sql-driver/mysql v1.5.0
github.com/google/go-cmp v0.5.0
github.com/google/go-cmp v0.5.0 //tests
github.com/google/uuid v1.1.1
github.com/jackc/pgx/v4 v4.11.0 //tests
github.com/lib/pq v1.7.0
github.com/pkg/profile v1.5.0
github.com/stretchr/testify v1.6.1
github.com/pkg/profile v1.5.0 //tests
github.com/shopspring/decimal v1.2.0 // tests
github.com/stretchr/testify v1.6.1 // tests
)

463
go.sum
View file

@ -1,23 +1,482 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-jet/jet v1.0.0 h1:ENxUe/6lH82qLykIGAdZIlskZrpTeNfxjHz4VHtkVmA=
github.com/go-jet/jet v2.3.0+incompatible h1:Yg7JSERDC0f9x3dHUBMA2cxe9/qC6qlozDDO/s38USU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.8.1 h1:ySBX7Q87vOMqKU2bbmKbUvtYhauDFclYbNDYIE1/h6s=
github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
github.com/jackc/pgtype v1.7.0 h1:6f4kVsW01QftE38ufBYxKciO6gyioXSC0ABIRLcZrGs=
github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE=
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-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.11.0 h1:J86tSWd3Y7nKjwT/43xZBvpi04keQWx8gNC2YkdJhZI=
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug=
github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View file

@ -45,19 +45,25 @@ func (s *ClauseSelect) Serialize(statementType StatementType, out *SQLBuilder, o
// ClauseFrom struct
type ClauseFrom struct {
Table Serializer
Tables []Serializer
}
// Serialize serializes clause into SQLBuilder
func (f *ClauseFrom) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
if f.Table == nil {
if len(f.Tables) == 0 { // SELECT statement does not have to have FROM clause
return
}
out.NewLine()
out.WriteString("FROM")
out.IncreaseIdent()
f.Table.serialize(statementType, out, FallTrough(options)...)
for i, table := range f.Tables {
if i > 0 {
out.WriteString(",")
out.NewLine()
}
table.serialize(statementType, out, FallTrough(options)...)
}
out.DecreaseIdent()
}
@ -302,7 +308,7 @@ func (s *SetClause) Serialize(statementType StatementType, out *SQLBuilder, opti
panic("jet: nil column in columns list for SET clause")
}
out.WriteString(column.Name())
out.WriteIdentifier(column.Name())
out.WriteString(" = ")

View file

@ -801,3 +801,8 @@ func newTimestampzFunc(name string, expressions ...Expression) *timestampzFunc {
return timestampzFunc
}
// Func can be used to call an custom or as of yet unsupported function in the database.
func Func(name string, expressions ...Expression) Expression {
return newFunc(name, expressions, nil)
}

View file

@ -176,3 +176,7 @@ func TestTO_ASCII(t *testing.T) {
assertClauseSerialize(t, TO_ASCII(String("Karel")), `TO_ASCII($1)`, "Karel")
assertClauseSerialize(t, TO_ASCII(String("Karel")), `TO_ASCII($1)`, "Karel")
}
func TestFunc(t *testing.T) {
assertClauseSerialize(t, Func("FOO", String("test"), NULL, MAX(Int(1))), "FOO($1, NULL, MAX($2))", "test", int64(1))
}

View file

@ -67,8 +67,7 @@ type integerLiteralExpression struct {
integerInterfaceImpl
}
// Int creates new integer literal
func Int(value int64) IntegerExpression {
func intLiteral(value interface{}) IntegerExpression {
numLiteral := &integerLiteralExpression{}
numLiteral.literalExpressionImpl = *literal(value)
@ -79,6 +78,46 @@ func Int(value int64) IntegerExpression {
return numLiteral
}
// Int creates a new 64 bit signed integer literal
func Int(value int64) IntegerExpression {
return intLiteral(value)
}
// Int8 creates a new 8 bit signed integer literal
func Int8(value int8) IntegerExpression {
return intLiteral(value)
}
// Int16 creates a new 16 bit signed integer literal
func Int16(value int16) IntegerExpression {
return intLiteral(value)
}
// Int32 creates a new 32 bit signed integer literal
func Int32(value int32) IntegerExpression {
return intLiteral(value)
}
// Uint8 creates a new 8 bit unsigned integer literal
func Uint8(value uint8) IntegerExpression {
return intLiteral(value)
}
// Uint16 creates a new 16 bit unsigned integer literal
func Uint16(value uint16) IntegerExpression {
return intLiteral(value)
}
// Uint32 creates a new 32 bit unsigned integer literal
func Uint32(value uint32) IntegerExpression {
return intLiteral(value)
}
// Uint64 creates a new 64 bit unsigned integer literal
func Uint64(value uint64) IntegerExpression {
return intLiteral(value)
}
//---------------------------------------------------//
type boolLiteralExpression struct {
boolInterfaceImpl
@ -101,7 +140,7 @@ type floatLiteral struct {
literalExpressionImpl
}
// Float creates new float literal
// Float creates new float literal from float64 value
func Float(value float64) FloatExpression {
floatLiteral := floatLiteral{}
floatLiteral.literalExpressionImpl = *literal(value)
@ -111,6 +150,16 @@ func Float(value float64) FloatExpression {
return &floatLiteral
}
// Decimal creates new float literal from string value
func Decimal(value string) FloatExpression {
floatLiteral := floatLiteral{}
floatLiteral.literalExpressionImpl = *literal(value)
floatLiteral.floatInterfaceImpl.parent = &floatLiteral
return &floatLiteral
}
//---------------------------------------------------//
type stringLiteral struct {
stringInterfaceImpl
@ -345,18 +394,94 @@ func WRAP(expression ...Expression) Expression {
type rawExpression struct {
ExpressionInterfaceImpl
Raw string
Raw string
NamedArgument map[string]interface{}
noWrap bool
}
func (n *rawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString(n.Raw)
if !n.noWrap && !contains(options, NoWrap) {
out.WriteByte('(')
}
out.insertRawQuery(n.Raw, n.NamedArgument)
if !n.noWrap && !contains(options, NoWrap) {
out.WriteByte(')')
}
}
// Raw can be used for any unsupported functions, operators or expressions.
// For example: Raw("current_database()")
func Raw(raw string, parent ...Expression) Expression {
rawExp := &rawExpression{Raw: raw}
func Raw(raw string, namedArgs ...map[string]interface{}) Expression {
var namedArguments map[string]interface{}
if len(namedArgs) > 0 {
namedArguments = namedArgs[0]
}
rawExp := &rawExpression{
Raw: raw,
NamedArgument: namedArguments,
}
rawExp.ExpressionInterfaceImpl.Parent = rawExp
return rawExp
}
// RawWithParent is a Raw constructor used for construction dialect specific expression
func RawWithParent(raw string, parent ...Expression) Expression {
rawExp := &rawExpression{
Raw: raw,
noWrap: true,
}
rawExp.ExpressionInterfaceImpl.Parent = OptionalOrDefaultExpression(rawExp, parent...)
return rawExp
}
// RawInt helper that for integer expressions
func RawInt(raw string, namedArgs ...map[string]interface{}) IntegerExpression {
return IntExp(Raw(raw, namedArgs...))
}
// RawFloat helper that for float expressions
func RawFloat(raw string, namedArgs ...map[string]interface{}) FloatExpression {
return FloatExp(Raw(raw, namedArgs...))
}
// RawString helper that for string expressions
func RawString(raw string, namedArgs ...map[string]interface{}) StringExpression {
return StringExp(Raw(raw, namedArgs...))
}
// RawTime helper that for time expressions
func RawTime(raw string, namedArgs ...map[string]interface{}) TimeExpression {
return TimeExp(Raw(raw, namedArgs...))
}
// RawTimez helper that for time with time zone expressions
func RawTimez(raw string, namedArgs ...map[string]interface{}) TimezExpression {
return TimezExp(Raw(raw, namedArgs...))
}
// RawTimestamp helper that for timestamp expressions
func RawTimestamp(raw string, namedArgs ...map[string]interface{}) TimestampExpression {
return TimestampExp(Raw(raw, namedArgs...))
}
// RawTimestampz helper that for timestamp with time zone expressions
func RawTimestampz(raw string, namedArgs ...map[string]interface{}) TimestampzExpression {
return TimestampzExp(Raw(raw, namedArgs...))
}
// RawDate helper that for date expressions
func RawDate(raw string, namedArgs ...map[string]interface{}) DateExpression {
return DateExp(Raw(raw, namedArgs...))
}
// UUID is a helper function to create string literal expression from uuid object
// value can be any uuid type with a String method
func UUID(value fmt.Stringer) StringExpression {
return String(value.String())
}

View file

@ -6,7 +6,7 @@ import (
)
func TestRawExpression(t *testing.T) {
assertClauseSerialize(t, Raw("current_database()"), "current_database()")
assertClauseSerialize(t, Raw("current_database()"), "(current_database())")
var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)

View file

@ -0,0 +1,47 @@
package jet
type rawStatementImpl struct {
serializerStatementInterfaceImpl
RawQuery string
NamedArguments map[string]interface{}
}
// RawStatement creates new sql statements from raw query and optional map of named arguments
func RawStatement(dialect Dialect, rawQuery string, namedArgument ...map[string]interface{}) Statement {
newRawStatement := rawStatementImpl{
serializerStatementInterfaceImpl: serializerStatementInterfaceImpl{
dialect: dialect,
statementType: "",
parent: nil,
},
RawQuery: rawQuery,
}
if len(namedArgument) > 0 {
newRawStatement.NamedArguments = namedArgument[0]
}
newRawStatement.parent = &newRawStatement
return &newRawStatement
}
func (s *rawStatementImpl) projections() ProjectionList {
return nil
}
func (s *rawStatementImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if !contains(options, NoWrap) {
out.WriteString("(")
out.IncreaseIdent()
}
out.insertRawQuery(s.RawQuery, s.NamedArguments)
if !contains(options, NoWrap) {
out.DecreaseIdent()
out.NewLine()
out.WriteString(")")
}
}

View file

@ -13,8 +13,8 @@ type selectTableImpl struct {
}
// NewSelectTable func
func NewSelectTable(selectStmt SerializerStatement, alias string) SelectTable {
selectTable := &selectTableImpl{selectStmt: selectStmt, alias: alias}
func NewSelectTable(selectStmt SerializerStatement, alias string) selectTableImpl {
selectTable := selectTableImpl{selectStmt: selectStmt, alias: alias}
return selectTable
}
@ -38,3 +38,22 @@ func (s selectTableImpl) serialize(statement StatementType, out *SQLBuilder, opt
out.WriteString("AS")
out.WriteIdentifier(s.alias)
}
// --------------------------------------
type lateralImpl struct {
selectTableImpl
}
// NewLateral creates new lateral expression from select statement with alias
func NewLateral(selectStmt SerializerStatement, alias string) SelectTable {
return lateralImpl{selectTableImpl: NewSelectTable(selectStmt, alias)}
}
func (s lateralImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString("LATERAL")
s.selectStmt.serialize(statement, out)
out.WriteString("AS")
out.WriteIdentifier(s.alias)
}

View file

@ -7,6 +7,7 @@ import (
"github.com/go-jet/jet/v2/internal/utils"
"github.com/google/uuid"
"reflect"
"sort"
"strconv"
"strings"
"time"
@ -135,6 +136,73 @@ func (s *SQLBuilder) insertParametrizedArgument(arg interface{}) {
s.WriteString(argPlaceholder)
}
func (s *SQLBuilder) insertRawQuery(raw string, namedArg map[string]interface{}) {
type namedArgumentPosition struct {
Name string
Value interface{}
Position int
}
var namedArgumentPositions []namedArgumentPosition
for namedArg, value := range namedArg {
rawCopy := raw
rawIndex := 0
exists := false
// one named argument can occur multiple times inside raw string
for {
index := strings.Index(rawCopy, namedArg)
if index == -1 {
break
}
exists = true
namedArgumentPositions = append(namedArgumentPositions, namedArgumentPosition{
Name: namedArg,
Value: value,
Position: rawIndex + index,
})
rawCopy = rawCopy[index+len(namedArg):]
rawIndex += index + len(namedArg)
}
if !exists {
panic("jet: named argument '" + namedArg + "' does not appear in raw query")
}
}
sort.Slice(namedArgumentPositions, func(i, j int) bool {
return namedArgumentPositions[i].Position < namedArgumentPositions[j].Position
})
for _, namedArgumentPos := range namedArgumentPositions {
// if named argument does not exists in raw string do not add argument to the list of arguments
// It can happen if the same argument occurs multiple times in postgres query.
if !strings.Contains(raw, namedArgumentPos.Name) {
continue
}
s.Args = append(s.Args, namedArgumentPos.Value)
currentArgNum := len(s.Args)
placeholder := s.Dialect.ArgumentPlaceholder()(currentArgNum)
// if placeholder is not unique identifier ($1, $2, etc..), we will replace just one occurrence of the argument
toReplace := -1 // all occurrences
if placeholder == "?" {
toReplace = 1 // just one occurrence
}
if s.Debug {
placeholder = argToString(namedArgumentPos.Value)
}
raw = strings.Replace(raw, namedArgumentPos.Name, placeholder, toReplace)
}
s.WriteString(raw)
}
func argToString(value interface{}) string {
if utils.IsNil(value) {
return "NULL"

View file

@ -13,19 +13,30 @@ type Statement interface {
// DebugSql returns debug query where every parametrized placeholder is replaced with its argument.
// Do not use it in production. Use it only for debug purposes.
DebugSql() (query string)
// Query executes statement over database connection db and stores row result in destination.
// Query executes statement over database connection/transaction db and stores row result in destination.
// Destination can be either pointer to struct or pointer to a slice.
// If destination is pointer to struct and query result set is empty, method returns qrm.ErrNoRows.
Query(db qrm.DB, destination interface{}) error
// QueryContext executes statement with a context over database connection db and stores row result in destination.
// QueryContext executes statement with a context over database connection/transaction db and stores row result in destination.
// Destination can be either pointer to struct or pointer to a slice.
// If destination is pointer to struct and query result set is empty, method returns qrm.ErrNoRows.
QueryContext(ctx context.Context, db qrm.DB, destination interface{}) error
//Exec executes statement over db connection without returning any rows.
//Exec executes statement over db connection/transaction without returning any rows.
Exec(db qrm.DB) (sql.Result, error)
//Exec executes statement with context over db connection without returning any rows.
//Exec executes statement with context over db connection/transaction without returning any rows.
ExecContext(ctx context.Context, db qrm.DB) (sql.Result, error)
// Rows executes statements over db connection/transaction and returns rows
Rows(ctx context.Context, db qrm.DB) (*Rows, error)
}
// Rows wraps sql.Rows type to add query result mapping for Scan method
type Rows struct {
*sql.Rows
}
// Scan will map the Row values into struct destination
func (r *Rows) Scan(destination interface{}) error {
return qrm.ScanOneRowToDest(r.Rows, destination)
}
// SerializerStatement interface
@ -99,6 +110,20 @@ func (s *serializerStatementInterfaceImpl) ExecContext(ctx context.Context, db q
return db.ExecContext(ctx, query, args...)
}
func (s *serializerStatementInterfaceImpl) Rows(ctx context.Context, db qrm.DB) (*Rows, error) {
query, args := s.Sql()
callLogger(ctx, s)
rows, err := db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
return &Rows{rows}, nil
}
func callLogger(ctx context.Context, statement Statement) {
if logger != nil {
logger(ctx, statement)

View file

@ -15,20 +15,27 @@ type Table interface {
columns() []Column
SchemaName() string
TableName() string
AS(alias string)
Alias() string
}
// NewTable creates new table with schema Name, table Name and list of columns
func NewTable(schemaName, name string, columns ...ColumnExpression) SerializerTable {
func NewTable(schemaName, name, alias string, columns ...ColumnExpression) SerializerTable {
t := tableImpl{
schemaName: schemaName,
name: name,
alias: alias,
columnList: columns,
}
columnTableName := name
if alias != "" {
columnTableName = alias
}
for _, c := range columns {
c.setTableName(name)
c.setTableName(columnTableName)
}
return &t
@ -41,14 +48,6 @@ type tableImpl struct {
columnList []ColumnExpression
}
func (t *tableImpl) AS(alias string) {
t.alias = alias
for _, c := range t.columnList {
c.setTableName(alias)
}
}
func (t *tableImpl) SchemaName() string {
return t.schemaName
}
@ -67,13 +66,21 @@ func (t *tableImpl) columns() []Column {
return ret
}
func (t *tableImpl) Alias() string {
return t.alias
}
func (t *tableImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if t == nil {
panic("jet: tableImpl is nil")
}
out.WriteIdentifier(t.schemaName)
out.WriteString(".")
// Use default schema if the schema name is not set
if len(t.schemaName) > 0 {
out.WriteIdentifier(t.schemaName)
out.WriteString(".")
}
out.WriteIdentifier(t.name)
if len(t.alias) > 0 {
@ -129,9 +136,6 @@ func (t *joinTableImpl) TableName() string {
return ""
}
func (t *joinTableImpl) AS(alias string) {
}
func (t *joinTableImpl) columns() []Column {
var ret []Column
@ -145,6 +149,10 @@ func (t *joinTableImpl) columns() []Column {
return ret
}
func (t *joinTableImpl) Alias() string {
return ""
}
func (t *joinTableImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if t == nil {
panic("jet: Join table is nil. ")

View file

@ -6,7 +6,7 @@ import (
)
func TestNewTable(t *testing.T) {
newTable := NewTable("schema", "table", IntegerColumn("intCol"))
newTable := NewTable("schema", "table", "", IntegerColumn("intCol"))
require.Equal(t, newTable.SchemaName(), "schema")
require.Equal(t, newTable.TableName(), "table")
@ -16,8 +16,8 @@ func TestNewTable(t *testing.T) {
}
func TestNewJoinTable(t *testing.T) {
newTable1 := NewTable("schema", "table", IntegerColumn("intCol1"))
newTable2 := NewTable("schema", "table2", IntegerColumn("intCol2"))
newTable1 := NewTable("schema", "table", "", IntegerColumn("intCol1"))
newTable2 := NewTable("schema", "table2", "", IntegerColumn("intCol2"))
joinTable := NewJoinTable(newTable1, newTable2, InnerJoin, IntegerColumn("intCol1").EQ(IntegerColumn("intCol2")))

View file

@ -26,7 +26,7 @@ var (
table1ColBool = BoolColumn("col_bool")
table1ColDate = DateColumn("col_date")
)
var table1 = NewTable("db", "table1", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColTimestamp, table1ColTimestampz)
var table1 = NewTable("db", "table1", "", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColTimestamp, table1ColTimestampz)
var (
table2Col3 = IntegerColumn("col3")
@ -41,14 +41,14 @@ var (
table2ColTimestampz = TimestampzColumn("col_timestampz")
table2ColDate = DateColumn("col_date")
)
var table2 = NewTable("db", "table2", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz)
var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz)
var (
table3Col1 = IntegerColumn("col1")
table3ColInt = IntegerColumn("col_int")
table3StrCol = StringColumn("col2")
)
var table3 = NewTable("db", "table3", table3Col1, table3ColInt, table3StrCol)
var table3 = NewTable("db", "table3", "", table3Col1, table3ColInt, table3StrCol)
func assertClauseSerialize(t *testing.T, clause Serializer, query string, args ...interface{}) {
out := SQLBuilder{Dialect: defaultDialect}

View file

@ -8,6 +8,7 @@ import (
"github.com/go-jet/jet/v2/internal/utils"
"github.com/go-jet/jet/v2/qrm"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"io/ioutil"
"os"
@ -89,7 +90,7 @@ func AssertJSONFile(t *testing.T, data interface{}, testRelativePath string) {
// AssertStatementSql check if statement Sql() is the same as expectedQuery and expectedArgs
func AssertStatementSql(t *testing.T, query jet.Statement, expectedQuery string, expectedArgs ...interface{}) {
queryStr, args := query.Sql()
require.Equal(t, queryStr, expectedQuery)
assertQueryString(t, queryStr, expectedQuery)
if len(expectedArgs) == 0 {
return
@ -115,8 +116,8 @@ func AssertDebugStatementSql(t *testing.T, query jet.Statement, expectedQuery st
AssertDeepEqual(t, args, expectedArgs, "arguments are not equal")
}
debuqSql := query.DebugSql()
require.Equal(t, debuqSql, expectedQuery)
debugSql := query.DebugSql()
assertQueryString(t, debugSql, expectedQuery)
}
// AssertSerialize checks if clause serialize produces expected query and args
@ -133,18 +134,6 @@ func AssertSerialize(t *testing.T, dialect jet.Dialect, serializer jet.Serialize
}
}
// AssertClauseSerialize checks if clause serialize produces expected query and args
func AssertClauseSerialize(t *testing.T, dialect jet.Dialect, clause jet.Clause, query string, args ...interface{}) {
out := jet.SQLBuilder{Dialect: dialect}
clause.Serialize(jet.SelectStatementType, &out)
require.Equal(t, out.Buff.String(), query)
if len(args) > 0 {
AssertDeepEqual(t, out.Args, args)
}
}
// AssertDebugSerialize checks if clause serialize produces expected debug query and args
func AssertDebugSerialize(t *testing.T, dialect jet.Dialect, clause jet.Serializer, query string, args ...interface{}) {
out := jet.SQLBuilder{Dialect: dialect, Debug: true}
@ -157,6 +146,18 @@ func AssertDebugSerialize(t *testing.T, dialect jet.Dialect, clause jet.Serializ
}
}
// AssertClauseSerialize checks if clause serialize produces expected query and args
func AssertClauseSerialize(t *testing.T, dialect jet.Dialect, clause jet.Clause, query string, args ...interface{}) {
out := jet.SQLBuilder{Dialect: dialect}
clause.Serialize(jet.SelectStatementType, &out)
require.Equal(t, out.Buff.String(), query)
if len(args) > 0 {
AssertDeepEqual(t, out.Args, args)
}
}
// AssertPanicErr checks if running a function fun produces a panic with errorStr string
func AssertPanicErr(t *testing.T, fun func(), errorStr string) {
defer func() {
@ -194,7 +195,7 @@ func AssertQueryPanicErr(t *testing.T, stmt jet.Statement, db qrm.DB, dest inter
require.Equal(t, r, errString)
}()
stmt.Query(db, dest)
_ = stmt.Query(db, dest)
}
// AssertFileContent check if file content at filePath contains expectedContent text.
@ -223,7 +224,24 @@ func AssertFileNamesEqual(t *testing.T, fileInfos []os.FileInfo, fileNames ...st
// AssertDeepEqual checks if actual and expected objects are deeply equal.
func AssertDeepEqual(t *testing.T, actual, expected interface{}, msg ...string) {
require.True(t, cmp.Equal(actual, expected), msg)
if !assert.True(t, cmp.Equal(actual, expected), msg) {
printDiff(actual, expected)
t.FailNow()
}
}
func assertQueryString(t *testing.T, actual, expected string) {
if !assert.Equal(t, actual, expected) {
printDiff(actual, expected)
t.FailNow()
}
}
func printDiff(actual, expected interface{}) {
fmt.Println("Actual: ")
fmt.Println(actual)
fmt.Println("Expected: ")
fmt.Println(expected)
}
// BoolPtr returns address of bool parameter

View file

@ -7,7 +7,7 @@ type DeleteStatement interface {
Statement
WHERE(expression BoolExpression) DeleteStatement
ORDER_BY(orderByClauses ...jet.OrderByClause) DeleteStatement
ORDER_BY(orderByClauses ...OrderByClause) DeleteStatement
LIMIT(limit int64) DeleteStatement
}
@ -38,7 +38,7 @@ func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
return d
}
func (d *deleteStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) DeleteStatement {
func (d *deleteStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) DeleteStatement {
d.OrderBy.List = orderByClauses
return d
}

View file

@ -3,7 +3,7 @@ package mysql
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.
// Can be Bool, Int, Float, String, Date, Time or Timestamp expressions.
type Expression = jet.Expression
// BoolExpression interface
@ -70,9 +70,25 @@ var DateTimeExp = jet.TimestampExp
// Does not add sql cast to generated sql builder output.
var TimestampExp = jet.TimestampExp
// 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()")
var Raw = jet.Raw
// Raw helper methods for each of the mysql types
var (
Raw = jet.Raw
RawInt = jet.RawInt
RawFloat = jet.RawFloat
RawString = jet.RawString
RawTime = jet.RawTime
RawTimestamp = jet.RawTimestamp
RawDate = jet.RawDate
)
// Func can be used to call an custom or as of yet unsupported function in the database.
var Func = jet.Func
// NewEnumValue creates new named enum value
var NewEnumValue = jet.NewEnumValue

62
mysql/expressions_test.go Normal file
View file

@ -0,0 +1,62 @@
package mysql
import (
"testing"
time2 "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}),
"(? + table.colInt + ?)", 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("#1 + table.colInt + #2", RawArgs{"#1": 11, "#2": 22})),
"(? + (? + table.colInt + ?))",
int64(700), 11, 22)
assertDebugSerialize(t,
Int(700).ADD(RawInt("#1 + table.colInt + #2", RawArgs{"#1": 11, "#2": 22})),
"(700 + (11 + table.colInt + 22))")
}
func TestRawDuplicateArguments(t *testing.T) {
assertSerialize(t, Raw(":arg + table.colInt + :arg", RawArgs{":arg": 11}),
"(? + table.colInt + ?)", 11, 11)
assertSerialize(t, Raw("#age + table.colInt + #year + #age + #year + 11", RawArgs{"#age": 11, "#year": 2000}),
"(? + table.colInt + ? + ? + ? + 11)", 11, 2000, 11, 2000)
assertSerialize(t, Raw("#1 + all_types.integer + #2 + #1 + #2 + #3 + #4",
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}),
`(? + all_types.integer + ? + ? + ? + ? + ?)`, 11, 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}), "(table.colInt + ?)", 22)
}
func TestRawType(t *testing.T) {
assertSerialize(t, RawFloat("table.colInt + &float", RawArgs{"&float": 11.22}).EQ(Float(3.14)),
"((table.colInt + ?) = ?)", 11.22, 3.14)
assertSerialize(t, RawString("table.colStr || str", RawArgs{"str": "doe"}).EQ(String("john doe")),
"((table.colStr || ?) = ?)", "doe", "john doe")
time := time2.Now()
assertSerialize(t, RawTime("table.colTime").EQ(TimeT(time)),
"((table.colTime) = CAST(? AS TIME))", time)
assertSerialize(t, RawTimestamp("table.colTimestamp").EQ(TimestampT(time)),
"((table.colTimestamp) = TIMESTAMP(?))", time)
assertSerialize(t, RawDate("table.colDate").EQ(DateT(time)),
"((table.colDate) = CAST(? AS DATE))", time)
}

View file

@ -253,8 +253,3 @@ var EXISTS = jet.EXISTS
// CASE create CASE operator with optional list of expressions
var CASE = jet.CASE
//----------------- Bit operators ---------------//
// BIT_NOT inverts every bit in integer expression
var BIT_NOT = jet.BIT_NOT

View file

@ -97,7 +97,7 @@ func INTERVAL(value interface{}, unitType unitType) Interval {
// INTERVALe creates new temporal interval from expresion and unit type.
func INTERVALe(expr Expression, unitType unitType) Interval {
return jet.NewInterval(jet.ListSerializer{
Serializers: []jet.Serializer{expr, jet.Raw(string(unitType))},
Serializers: []jet.Serializer{expr, jet.RawWithParent(string(unitType))},
Separator: " ",
})
}

24
mysql/lateral.go Normal file
View file

@ -0,0 +1,24 @@
package mysql
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
}

View file

@ -15,15 +15,46 @@ var (
// Bool creates new bool literal expression
var Bool = jet.Bool
// Int is constructor for integer expressions literals.
// Int is constructor for 64 bit signed integer expressions literals.
var Int = jet.Int
// Float creates new float literal expression
// Int8 is constructor for 8 bit signed integer expressions literals.
var Int8 = jet.Int8
// Int16 is constructor for 16 bit signed integer expressions literals.
var Int16 = jet.Int16
// Int32 is constructor for 32 bit signed integer expressions literals.
var Int32 = jet.Int32
// Int64 is constructor for 64 bit signed integer expressions literals.
var Int64 = jet.Int
// Uint8 is constructor for 8 bit unsigned integer expressions literals.
var Uint8 = jet.Uint8
// Uint16 is constructor for 16 bit unsigned integer expressions literals.
var Uint16 = jet.Uint16
// Uint32 is constructor for 32 bit unsigned integer expressions literals.
var Uint32 = jet.Uint32
// Uint64 is constructor for 64 bit unsigned integer expressions literals.
var Uint64 = jet.Uint64
// Float creates new float literal expression from float64 value
var Float = jet.Float
// Decimal creates new float literal expression from string value
var Decimal = jet.Decimal
// String creates new string literal expression
var String = jet.String
// 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
// Date creates new date literal
var Date = func(year int, month time.Month, day int) DateExpression {
return CAST(jet.Date(year, month, day)).AS_DATE()

View file

@ -1,6 +1,7 @@
package mysql
import (
"math"
"testing"
"time"
)
@ -13,6 +14,46 @@ func TestInt(t *testing.T) {
assertSerialize(t, Int(11), `?`, int64(11))
}
func TestInt8(t *testing.T) {
val := int8(math.MinInt8)
assertSerialize(t, Int8(val), `?`, val)
}
func TestInt16(t *testing.T) {
val := int16(math.MinInt16)
assertSerialize(t, Int16(val), `?`, val)
}
func TestInt32(t *testing.T) {
val := int32(math.MinInt32)
assertSerialize(t, Int32(val), `?`, val)
}
func TestInt64(t *testing.T) {
val := int64(math.MinInt64)
assertSerialize(t, Int64(val), `?`, val)
}
func TestUint8(t *testing.T) {
val := uint8(math.MaxUint8)
assertSerialize(t, Uint8(val), `?`, val)
}
func TestUint16(t *testing.T) {
val := uint16(math.MaxUint16)
assertSerialize(t, Uint16(val), `?`, val)
}
func TestUint32(t *testing.T) {
val := uint32(math.MaxUint32)
assertSerialize(t, Uint32(val), `?`, val)
}
func TestUint64(t *testing.T) {
val := uint64(math.MaxUint64)
assertSerialize(t, Uint64(val), `?`, val)
}
func TestFloat(t *testing.T) {
assertSerialize(t, Float(12.34), `?`, float64(12.34))
}

9
mysql/operators.go Normal file
View file

@ -0,0 +1,9 @@
package mysql
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

View file

@ -41,12 +41,12 @@ type SelectStatement interface {
Expression
DISTINCT() SelectStatement
FROM(table ReadableTable) SelectStatement
FROM(tables ...ReadableTable) SelectStatement
WHERE(expression BoolExpression) SelectStatement
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
HAVING(boolExpression BoolExpression) SelectStatement
WINDOW(name string) windowExpand
ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement
ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
LIMIT(limit int64) SelectStatement
OFFSET(offset int64) SelectStatement
FOR(lock RowLock) SelectStatement
@ -70,7 +70,9 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
&newSelect.Limit, &newSelect.Offset, &newSelect.For, &newSelect.ShareLock)
newSelect.Select.ProjectionList = projections
newSelect.From.Table = table
if table != nil {
newSelect.From.Tables = []jet.Serializer{table}
}
newSelect.Limit.Count = -1
newSelect.Offset.Count = -1
newSelect.ShareLock.Name = "LOCK IN SHARE MODE"
@ -103,8 +105,11 @@ func (s *selectStatementImpl) DISTINCT() SelectStatement {
return s
}
func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
s.From.Table = table
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
s.From.Tables = nil
for _, table := range tables {
s.From.Tables = append(s.From.Tables, table)
}
return s
}
@ -128,7 +133,7 @@ func (s *selectStatementImpl) WINDOW(name string) windowExpand {
return windowExpand{selectStatement: s}
}
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement {
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) SelectStatement {
s.OrderBy.List = orderByClauses
return s
}

View file

@ -132,3 +132,25 @@ FROM db.table1
LOCK IN SHARE MODE;
`)
}
func TestSelect_NOT_EXISTS(t *testing.T) {
testutils.AssertStatementSql(t,
SELECT(table1ColInt).
FROM(table1).
WHERE(
NOT(EXISTS(
SELECT(table2ColInt).
FROM(table2).
WHERE(
table1ColInt.EQ(table2ColInt),
),
))), `
SELECT table1.col_int AS "table1.col_int"
FROM db.table1
WHERE (NOT (EXISTS (
SELECT table2.col_int AS "table2.col_int"
FROM db.table2
WHERE table1.col_int = table2.col_int
)));
`)
}

View file

@ -17,7 +17,7 @@ func UNION_ALL(lhs, rhs jet.SerializerStatement, selects ...jet.SerializerStatem
type setStatement interface {
setOperators
ORDER_BY(orderByClauses ...jet.OrderByClause) setStatement
ORDER_BY(orderByClauses ...OrderByClause) setStatement
LIMIT(limit int64) setStatement
OFFSET(offset int64) setStatement
@ -70,7 +70,7 @@ func newSetStatementImpl(operator string, all bool, selects []jet.SerializerStat
return newSetStatement
}
func (s *setStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) setStatement {
func (s *setStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) setStatement {
s.setOperator.OrderBy.List = orderByClauses
return s
}

8
mysql/statement.go Normal file
View file

@ -0,0 +1,8 @@
package mysql
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) Statement {
return jet.RawStatement(Dialect, rawQuery, namedArguments...)
}

View file

@ -77,9 +77,9 @@ func (r readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) joinSelectUp
}
// NewTable creates new table with schema Name, table Name and list of columns
func NewTable(schemaName, name string, columns ...jet.ColumnExpression) Table {
func NewTable(schemaName, name, alias string, columns ...jet.ColumnExpression) Table {
t := &tableImpl{
SerializerTable: jet.NewTable(schemaName, name, columns...),
SerializerTable: jet.NewTable(schemaName, name, alias, columns...),
}
t.readableTableInterfaceImpl.parent = t

View file

@ -17,5 +17,8 @@ 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
// SetLogger sets automatic statement logging
var SetLogger = jet.SetLoggerFunc

View file

@ -2,6 +2,7 @@ package mysql
import (
"fmt"
"strings"
"testing"
)
@ -52,11 +53,29 @@ WHERE table1.col1 = ?;
).
WHERE(table1Col1.EQ(Int(2)))
//fmt.Println(stmt.Sql())
assertStatementSql(t, stmt, expectedSQL, int64(2))
}
func TestUpdateReservedWorldColumn(t *testing.T) {
type table struct {
Load string
}
loadColumn := StringColumn("Load")
assertStatementSql(t,
table1.UPDATE(loadColumn).
MODEL(
table{
Load: "foo",
},
).
WHERE(loadColumn.EQ(String("bar"))), strings.Replace(`
UPDATE db.table1
SET ''Load'' = ?
WHERE ''Load'' = ?;
`, "''", "`", -1), "foo", "bar")
}
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 for SET clause")

View file

@ -16,19 +16,7 @@ var table1ColTimestamp = TimestampColumn("col_timestamp")
var table1ColDate = DateColumn("col_date")
var table1ColTime = TimeColumn("col_time")
var table1 = NewTable(
"db",
"table1",
table1Col1,
table1ColInt,
table1ColFloat,
table1ColString,
table1Col3,
table1ColBool,
table1ColDate,
table1ColTimestamp,
table1ColTime,
)
var table1 = NewTable("db", "table1", "", table1Col1, table1ColInt, table1ColFloat, table1ColString, table1Col3, table1ColBool, table1ColDate, table1ColTimestamp, table1ColTime)
var table2Col3 = IntegerColumn("col3")
var table2Col4 = IntegerColumn("col4")
@ -39,28 +27,12 @@ var table2ColBool = BoolColumn("col_bool")
var table2ColTimestamp = TimestampColumn("col_timestamp")
var table2ColDate = DateColumn("col_date")
var table2 = NewTable(
"db",
"table2",
table2Col3,
table2Col4,
table2ColInt,
table2ColFloat,
table2ColStr,
table2ColBool,
table2ColDate,
table2ColTimestamp,
)
var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColDate, table2ColTimestamp)
var table3Col1 = IntegerColumn("col1")
var table3ColInt = IntegerColumn("col_int")
var table3StrCol = StringColumn("col2")
var table3 = NewTable(
"db",
"table3",
table3Col1,
table3ColInt,
table3StrCol)
var table3 = NewTable("db", "table3", "", table3Col1, table3ColInt, table3StrCol)
func assertSerialize(t *testing.T, clause jet.Serializer, query string, args ...interface{}) {
testutils.AssertSerialize(t, Dialect, clause, query, args...)

View file

@ -80,13 +80,7 @@ func TestReservedWordEscaped(t *testing.T) {
var table1ColVariadic = IntervalColumn("VARIADIC")
var table1ColProcedure = IntervalColumn("procedure")
_ = NewTable(
"db",
"table1",
table1ColUser,
table1ColVariadic,
table1ColProcedure,
)
_ = NewTable("db", "table1", "", table1ColUser, table1ColVariadic, table1ColProcedure)
assertSerialize(t, table1ColUser, `table1."user"`)
assertSerialize(t, table1ColVariadic, `table1."VARIADIC"`)

View file

@ -81,9 +81,27 @@ var TimestampExp = jet.TimestampExp
// Does not add sql cast to generated sql builder output.
var TimestampzExp = jet.TimestampzExp
// 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()")
var Raw = jet.Raw
// Raw helper methods for each of the postgres types
var (
Raw = jet.Raw
RawInt = jet.RawInt
RawFloat = jet.RawFloat
RawString = jet.RawString
RawTime = jet.RawTime
RawTimez = jet.RawTimez
RawTimestamp = jet.RawTimestamp
RawTimestampz = jet.RawTimestampz
RawDate = jet.RawDate
)
// Func can be used to call an custom or as of yet unsupported function in the database.
var Func = jet.Func
// NewEnumValue creates new named enum value
var NewEnumValue = jet.NewEnumValue

View file

@ -0,0 +1,76 @@
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, 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)", "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)
}

View file

@ -128,7 +128,7 @@ func INTERVAL(quantityAndUnit ...quantityAndUnit) IntervalExpression {
newInterval := &intervalExpression{}
newInterval.Expression = jet.Raw(intervalStr, newInterval)
newInterval.Expression = jet.RawWithParent(intervalStr, newInterval)
newInterval.intervalInterfaceImpl.parent = newInterval
return newInterval

24
postgres/lateral.go Normal file
View 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
postgres/lateral_test.go Normal file
View 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`)
}

View file

@ -1,25 +1,62 @@
package postgres
import (
"github.com/go-jet/jet/v2/internal/jet"
"time"
"github.com/go-jet/jet/v2/internal/jet"
)
// Bool creates new bool literal expression
var Bool = jet.Bool
// Int creates new integer literal expression
// Int is constructor for 64 bit signed integer expressions literals.
var Int = jet.Int
// Int8 is constructor for 8 bit signed integer expressions literals.
var Int8 = jet.Int8
// Int16 is constructor for 16 bit signed integer expressions literals.
var Int16 = jet.Int16
// Int32 is constructor for 32 bit signed integer expressions literals.
var Int32 = jet.Int32
// Int64 is constructor for 64 bit signed integer expressions literals.
var Int64 = jet.Int
// Uint8 is constructor for 8 bit unsigned integer expressions literals.
var Uint8 = jet.Uint8
// Uint16 is constructor for 16 bit unsigned integer expressions literals.
var Uint16 = jet.Uint16
// Uint32 is constructor for 32 bit unsigned integer expressions literals.
var Uint32 = jet.Uint32
// Uint64 is constructor for 64 bit unsigned integer expressions literals.
var Uint64 = jet.Uint64
// Float creates new float literal expression
var Float = jet.Float
// Decimal creates new float literal expression
var Decimal = jet.Decimal
// String creates new string literal expression
var String = jet.String
// Bytea craates new bytea literal expression
var Bytea = func(value string) StringExpression {
return CAST(jet.String(value)).AS_BYTEA()
// 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
var Bytea = func(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

View file

@ -1,6 +1,7 @@
package postgres
import (
"math"
"testing"
"time"
)
@ -13,6 +14,46 @@ 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`, val)
}
func TestInt16(t *testing.T) {
val := int16(math.MinInt16)
assertSerialize(t, Int16(val), `$1`, val)
}
func TestInt32(t *testing.T) {
val := int32(math.MinInt32)
assertSerialize(t, Int32(val), `$1`, val)
}
func TestInt64(t *testing.T) {
val := int64(math.MinInt64)
assertSerialize(t, Int64(val), `$1`, val)
}
func TestUint8(t *testing.T) {
val := uint8(math.MaxUint8)
assertSerialize(t, Uint8(val), `$1`, val)
}
func TestUint16(t *testing.T) {
val := uint16(math.MaxUint16)
assertSerialize(t, Uint16(val), `$1`, val)
}
func TestUint32(t *testing.T) {
val := uint32(math.MaxUint32)
assertSerialize(t, Uint32(val), `$1`, val)
}
func TestUint64(t *testing.T) {
val := uint64(math.MaxUint64)
assertSerialize(t, Uint64(val), `$1`, val)
}
func TestFloat(t *testing.T) {
assertSerialize(t, Float(12.34), `$1`, float64(12.34))
}
@ -21,6 +62,11 @@ func TestString(t *testing.T) {
assertSerialize(t, String("Some text"), `$1`, "Some text")
}
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 TestDate(t *testing.T) {
assertSerialize(t, Date(2014, time.January, 2), `$1::date`, "2014-01-02")
assertSerialize(t, DateT(time.Now()), `$1::date`)

View file

@ -44,12 +44,12 @@ type SelectStatement interface {
Expression
DISTINCT() SelectStatement
FROM(table ReadableTable) SelectStatement
FROM(tables ...ReadableTable) SelectStatement
WHERE(expression BoolExpression) SelectStatement
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
HAVING(boolExpression BoolExpression) SelectStatement
WINDOW(name string) windowExpand
ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement
ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
LIMIT(limit int64) SelectStatement
OFFSET(offset int64) SelectStatement
FOR(lock RowLock) SelectStatement
@ -76,7 +76,9 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
&newSelect.Limit, &newSelect.Offset, &newSelect.For)
newSelect.Select.ProjectionList = projections
newSelect.From.Table = table
if table != nil {
newSelect.From.Tables = []jet.Serializer{table}
}
newSelect.Limit.Count = -1
newSelect.Offset.Count = -1
@ -106,8 +108,11 @@ func (s *selectStatementImpl) DISTINCT() SelectStatement {
return s
}
func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
s.From.Table = table
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
s.From.Tables = nil
for _, table := range tables {
s.From.Tables = append(s.From.Tables, table)
}
return s
}
@ -131,7 +136,7 @@ func (s *selectStatementImpl) WINDOW(name string) windowExpand {
return windowExpand{selectStatement: s}
}
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement {
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) SelectStatement {
s.OrderBy.List = orderByClauses
return s
}

View file

@ -41,7 +41,7 @@ func EXCEPT_ALL(lhs, rhs jet.SerializerStatement) setStatement {
type setStatement interface {
setOperators
ORDER_BY(orderByClauses ...jet.OrderByClause) setStatement
ORDER_BY(orderByClauses ...OrderByClause) setStatement
LIMIT(limit int64) setStatement
OFFSET(offset int64) setStatement
@ -114,7 +114,7 @@ func newSetStatementImpl(operator string, all bool, selects []jet.SerializerStat
return newSetStatement
}
func (s *setStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) setStatement {
func (s *setStatementImpl) ORDER_BY(orderByClauses ...OrderByClause) setStatement {
s.setOperator.OrderBy.List = orderByClauses
return s
}

8
postgres/statement.go Normal file
View file

@ -0,0 +1,8 @@
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) Statement {
return jet.RawStatement(Dialect, rawQuery, namedArguments...)
}

View file

@ -109,10 +109,10 @@ type tableImpl struct {
}
// NewTable creates new table with schema Name, table Name and list of columns
func NewTable(schemaName, name string, columns ...jet.ColumnExpression) Table {
func NewTable(schemaName, name, alias string, columns ...jet.ColumnExpression) Table {
t := &tableImpl{
SerializerTable: jet.NewTable(schemaName, name, columns...),
SerializerTable: jet.NewTable(schemaName, name, alias, columns...),
}
t.readableTableInterfaceImpl.parent = t

View file

@ -99,3 +99,26 @@ CROSS JOIN db.table2`)
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;
`)
}

View file

@ -17,5 +17,8 @@ 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
// SetLogger sets automatic statement logging
var SetLogger = jet.SetLoggerFunc

View file

@ -21,6 +21,7 @@ var table1ColInterval = IntervalColumn("col_interval")
var table1 = NewTable(
"db",
"table1",
"",
table1Col1,
table1ColInt,
table1ColFloat,
@ -46,37 +47,21 @@ var table2ColTimestampz = TimestampzColumn("col_timestampz")
var table2ColDate = DateColumn("col_date")
var table2ColInterval = IntervalColumn("col_interval")
var table2 = NewTable(
"db",
"table2",
table2Col3,
table2Col4,
table2ColInt,
table2ColFloat,
table2ColStr,
table2ColBool,
table2ColTime,
table2ColTimez,
table2ColDate,
table2ColTimestamp,
table2ColTimestampz,
table2ColInterval,
)
var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz, table2ColInterval)
var table3Col1 = IntegerColumn("col1")
var table3ColInt = IntegerColumn("col_int")
var table3StrCol = StringColumn("col2")
var table3 = NewTable(
"db",
"table3",
table3Col1,
table3ColInt,
table3StrCol)
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...)
}

View file

@ -5,7 +5,8 @@ import (
"database/sql"
)
// DB is common database interface used by jet execution
// DB is common database interface used by query result mapping
// Both *sql.DB and *sql.Tx implements DB interface
type DB interface {
Exec(query string, args ...interface{}) (sql.Result, error)
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

View file

@ -2,9 +2,12 @@ package qrm
import (
"context"
"database/sql"
"errors"
"github.com/go-jet/jet/v2/internal/utils"
"fmt"
"reflect"
"github.com/go-jet/jet/v2/internal/utils"
)
// ErrNoRows is returned by Query when query result set is empty
@ -56,6 +59,52 @@ func Query(ctx context.Context, db DB, query string, args []interface{}, destPtr
}
}
// ScanOneRowToDest will scan one row into struct destination
func ScanOneRowToDest(rows *sql.Rows, destPtr interface{}) error {
utils.MustBeInitializedPtr(destPtr, "jet: destination is nil")
utils.MustBe(destPtr, reflect.Ptr, "jet: destination has to be a pointer to slice or pointer to struct")
scanContext, err := newScanContext(rows)
if err != nil {
return fmt.Errorf("failed to create scan context, %w", err)
}
if len(scanContext.row) == 0 {
return errors.New("empty row slice")
}
err = rows.Scan(scanContext.row...)
if err != nil {
return fmt.Errorf("rows scan error, %w", err)
}
destinationPtrType := reflect.TypeOf(destPtr)
tempSlicePtrValue := reflect.New(reflect.SliceOf(destinationPtrType))
tempSliceValue := tempSlicePtrValue.Elem()
_, err = mapRowToSlice(scanContext, "", tempSlicePtrValue, nil)
if err != nil {
return fmt.Errorf("failed to map a row, %w", err)
}
// edge case when row result set contains only NULLs.
if tempSliceValue.Len() == 0 {
return nil
}
destValue := reflect.ValueOf(destPtr).Elem()
firstTempSliceValue := tempSliceValue.Index(0).Elem()
if destValue.Type().AssignableTo(firstTempSliceValue.Type()) {
destValue.Set(tempSliceValue.Index(0).Elem())
}
return nil
}
func queryToSlice(ctx context.Context, db DB, query string, args []interface{}, slicePtr interface{}) (rowsProcessed int64, err error) {
if ctx == nil {
ctx = context.Background()

View file

@ -7,6 +7,7 @@ import (
"github.com/go-jet/jet/v2/qrm/internal"
"github.com/google/uuid"
"reflect"
"strconv"
"strings"
"time"
)
@ -182,12 +183,16 @@ func isIntegerType(value reflect.Type) bool {
return false
}
func tryAssign(source, destination reflect.Value) bool {
if source.Type().ConvertibleTo(destination.Type()) {
source = source.Convert(destination.Type())
}
func isNumber(valueType reflect.Type) bool {
return isIntegerType(valueType) || valueType == float64Type || valueType == float32Type
}
if isIntegerType(source.Type()) && destination.Type() == boolType {
func tryAssign(source, destination reflect.Value) bool {
switch {
case source.Type().ConvertibleTo(destination.Type()):
source = source.Convert(destination.Type())
case isIntegerType(source.Type()) && destination.Type() == boolType:
intValue := source.Int()
if intValue == 1 {
@ -195,6 +200,18 @@ func tryAssign(source, destination reflect.Value) bool {
} else if intValue == 0 {
source = reflect.ValueOf(false)
}
case source.Type() == stringType && isNumber(destination.Type()):
// if source is string and destination is a number(int8, int32, float32, ...), we first parse string to float64 number
// and then parsed number is converted into destination type
f, err := strconv.ParseFloat(source.String(), 64)
if err != nil {
return false
}
source = reflect.ValueOf(f)
if source.Type().ConvertibleTo(destination.Type()) {
source = source.Convert(destination.Type())
}
}
if source.Type().AssignableTo(destination.Type()) {
@ -281,6 +298,9 @@ var int32Type = reflect.TypeOf(int32(1))
var uint32Type = reflect.TypeOf(uint32(1))
var int64Type = reflect.TypeOf(int64(1))
var uint64Type = reflect.TypeOf(uint64(1))
var float32Type = reflect.TypeOf(float32(1))
var float64Type = reflect.TypeOf(float64(1))
var stringType = reflect.TypeOf("")
var nullBoolType = reflect.TypeOf(sql.NullBool{})
var nullInt8Type = reflect.TypeOf(internal.NullInt8{})
@ -308,7 +328,7 @@ func newScanType(columnType *sql.ColumnType) reflect.Type {
return nullStringType
case "FLOAT4":
return nullFloat32Type
case "FLOAT8", "NUMERIC", "DECIMAL", "FLOAT", "DOUBLE":
case "FLOAT8", "FLOAT", "DOUBLE":
return nullFloat64Type
case "BOOL":
return nullBoolType

View file

@ -35,3 +35,48 @@ func TestIsSimpleModelType(t *testing.T) {
require.Equal(t, isSimpleModelType(reflect.TypeOf([]string{"str"})), false)
require.Equal(t, isSimpleModelType(reflect.TypeOf([]int{1, 2})), false)
}
func TestTryAssign(t *testing.T) {
convertible := int16(16)
intBool1 := int32(1)
intBool0 := int32(0)
intBool2 := int32(2)
floatStr := "1.11"
floatErr := "1.abcd2"
str := "some string"
destination := struct {
Convertible int64
IntBool1 bool
IntBool0 bool
IntBool2 bool
FloatStr float64
FloatErr float64
Str string
}{}
testValue := reflect.ValueOf(&destination).Elem()
// convertible
require.True(t, tryAssign(reflect.ValueOf(convertible), testValue.FieldByName("Convertible")))
require.Equal(t, int64(16), destination.Convertible)
// 1/0 to bool
require.True(t, tryAssign(reflect.ValueOf(intBool1), testValue.FieldByName("IntBool1")))
require.Equal(t, true, destination.IntBool1)
require.True(t, tryAssign(reflect.ValueOf(intBool0), testValue.FieldByName("IntBool0")))
require.Equal(t, false, destination.IntBool0)
require.False(t, tryAssign(reflect.ValueOf(intBool2), testValue.FieldByName("IntBool2")))
require.Equal(t, false, destination.IntBool2)
// string to float
require.True(t, tryAssign(reflect.ValueOf(floatStr), testValue.FieldByName("FloatStr")))
require.Equal(t, 1.11, destination.FloatStr)
require.False(t, tryAssign(reflect.ValueOf(floatErr), testValue.FieldByName("FloatErr")))
require.Equal(t, 0.00, destination.FloatErr)
// string to string
require.True(t, tryAssign(reflect.ValueOf(str), testValue.FieldByName("Str")))
require.Equal(t, str, destination.Str)
}

View file

@ -46,6 +46,7 @@ func initMySQLDB() {
mySQLDBs := []string{
"dvds",
"dvds2",
"test_sample",
}
@ -89,6 +90,7 @@ func initPostgresDB() {
"dvds",
"test_sample",
"chinook",
"chinook2",
"northwind",
}

View file

@ -1,7 +1,7 @@
package mysql
import (
"fmt"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/require"
"strings"
"testing"
@ -78,7 +78,7 @@ func TestUUID(t *testing.T) {
require.NoError(t, err)
require.True(t, dest.StrUUID != nil)
require.True(t, dest.UUID.String() != uuid.UUID{}.String())
require.True(t, dest.StrUUID.String() != uuid.UUID{}.String())
require.Equal(t, dest.StrUUID.String(), "dc8daae3-b83b-11e9-8eb4-98ded00c39c6")
require.Equal(t, dest.StrUUID.String(), dest.BinUUID.String())
requireLogged(t, query)
}
@ -89,14 +89,17 @@ func TestExpressionOperators(t *testing.T) {
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
Raw("CURRENT_USER()").AS("result.raw"),
Raw(":first + COALESCE(all_types.small_int_ptr, 0) + :second", RawArgs{":first": 78, ":second": 56}).
AS("result.raw_arg"),
Raw("#1 + all_types.integer + #2 + #1 + #3 + #4", RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}).
AS("result.raw_arg2"),
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
AllTypes.SmallIntPtr.NOT_IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.not_in_select"),
Raw("DATABASE()"),
).LIMIT(2)
//fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, strings.Replace(`
SELECT all_types.'integer' IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
@ -105,46 +108,34 @@ SELECT all_types.'integer' IS NULL AS "result.is_null",
SELECT all_types.'integer' AS "all_types.integer"
FROM test_sample.all_types
))) AS "result.in_select",
(CURRENT_USER()) AS "result.raw",
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN ((
SELECT all_types.'integer' AS "all_types.integer"
FROM test_sample.all_types
))) AS "result.not_in_select",
DATABASE()
))) AS "result.not_in_select"
FROM test_sample.all_types
LIMIT ?;
`, "'", "`", -1), int64(11), int64(22), int64(11), int64(22), int64(2))
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
var dest []struct {
common.ExpressionTestResult `alias:"result.*"`
}
err := query.Query(db, &dest)
require.NoError(t, err)
//testutils.PrintJson(dest)
testutils.AssertJSON(t, dest, `
[
{
"IsNull": false,
"IsNotNull": true,
"In": false,
"InSelect": false,
"NotIn": null,
"NotInSelect": true
},
{
"IsNull": false,
"IsNotNull": false,
"In": null,
"InSelect": null,
"NotIn": null,
"NotInSelect": null
}
]
`)
require.Equal(t, *dest[0].IsNull, false)
require.Equal(t, *dest[0].IsNotNull, true)
require.Equal(t, *dest[0].In, false)
require.Equal(t, *dest[0].InSelect, false)
require.True(t, strings.Contains(*dest[0].Raw, "jet"))
require.Equal(t, *dest[0].RawArg, int32(148))
require.Equal(t, *dest[0].RawArg2, int32(-1479))
require.Nil(t, dest[0].NotIn)
require.Equal(t, *dest[0].NotInSelect, true)
}
func TestBoolOperators(t *testing.T) {
@ -974,7 +965,7 @@ func TestAllTypesInsert(t *testing.T) {
stmt := AllTypes.INSERT(AllTypes.AllColumns).
MODEL(toInsert)
fmt.Println(stmt.DebugSql())
//fmt.Println(stmt.DebugSql())
testutils.AssertExec(t, stmt, tx, 1)
@ -1028,7 +1019,7 @@ func TestAllTypesInsertOnDuplicateKeyUpdate(t *testing.T) {
AllTypes.Date.SET(DateT(time.Now())),
)
fmt.Println(stmt.DebugSql())
//fmt.Println(stmt.DebugSql())
_, err = stmt.Exec(tx)
require.NoError(t, err)
@ -1257,7 +1248,7 @@ FROM test_sample.user;
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.PrintJson(dest)
//testutils.PrintJson(dest)
testutils.AssertJSON(t, dest, `
[
@ -1279,3 +1270,99 @@ FROM test_sample.user;
]
`)
}
func TestExactDecimals(t *testing.T) {
type floats struct {
model.Floats
Numeric decimal.Decimal
NumericPtr decimal.Decimal
Decimal decimal.Decimal
DecimalPtr decimal.Decimal
}
t.Run("should query decimal", func(t *testing.T) {
query := SELECT(
Floats.AllColumns,
).FROM(
Floats,
).WHERE(Floats.Decimal.EQ(Decimal("1.11111111111111111111")))
var result floats
err := query.Query(db, &result)
require.NoError(t, err)
require.Equal(t, "1.11111111111111111111", result.Decimal.String())
require.Equal(t, "0", result.DecimalPtr.String()) // NULL
require.Equal(t, "2.22222222222222222222", result.Numeric.String())
require.Equal(t, "0", result.NumericPtr.String()) // NULL
require.Equal(t, 1.1111111111111112, result.Floats.Decimal) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.DecimalPtr)
require.Equal(t, 2.2222222222222223, result.Floats.Numeric) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.NumericPtr)
// floating point
require.Equal(t, 3.3333333, result.Floats.Float) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.FloatPtr)
require.Equal(t, 4.444444444444445, result.Floats.Double) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.DoublePtr)
require.Equal(t, 5.555555555555555, result.Floats.Real) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.RealPtr)
})
t.Run("should insert decimal", func(t *testing.T) {
insertQuery := Floats.INSERT(
Floats.AllColumns,
).MODEL(
floats{
Floats: model.Floats{
// overwritten by wrapped(floats) scope
Numeric: 0.1,
NumericPtr: testutils.Float64Ptr(0.1),
Decimal: 0.1,
DecimalPtr: testutils.Float64Ptr(0.1),
// not overwritten
Float: 0.2,
FloatPtr: testutils.Float64Ptr(0.22),
Double: 0.3,
DoublePtr: testutils.Float64Ptr(0.33),
Real: 0.4,
RealPtr: testutils.Float64Ptr(0.44),
},
Numeric: decimal.RequireFromString("12.35"),
NumericPtr: decimal.RequireFromString("56.79"),
Decimal: decimal.RequireFromString("91.23"),
DecimalPtr: decimal.RequireFromString("45.67"),
},
)
testutils.AssertDebugStatementSql(t, insertQuery, strings.Replace(`
INSERT INTO test_sample.floats (''decimal'', decimal_ptr, ''numeric'', numeric_ptr, ''float'', float_ptr, ''double'', double_ptr, ''real'', real_ptr)
VALUES ('91.23', '45.67', '12.35', '56.79', 0.2, 0.22, 0.3, 0.33, 0.4, 0.44);
`, "''", "`", -1))
_, err := insertQuery.Exec(db)
require.NoError(t, err)
var result floats
err = SELECT(Floats.AllColumns).
FROM(Floats).
WHERE(Floats.Numeric.EQ(Float(12.35))).
Query(db, &result)
require.NoError(t, err)
require.Equal(t, "12.35", result.Numeric.String())
require.Equal(t, "56.79", result.NumericPtr.String())
require.Equal(t, "91.23", result.Decimal.String())
require.Equal(t, "45.67", result.DecimalPtr.String())
require.Equal(t, 12.35, result.Floats.Numeric)
require.Equal(t, 56.79, *result.Floats.NumericPtr)
require.Equal(t, 91.23, result.Floats.Decimal)
require.Equal(t, 45.67, *result.Floats.DecimalPtr)
})
}

View file

@ -35,12 +35,7 @@ func TestGenerator(t *testing.T) {
}
func TestCmdGenerator(t *testing.T) {
goInstallJet := exec.Command("sh", "-c", "cd $GOPATH/src/ && GO111MODULE=off go get github.com/go-jet/jet/cmd/jet")
goInstallJet.Stderr = os.Stderr
err := goInstallJet.Run()
require.NoError(t, err)
err = os.RemoveAll(genTestDir3)
err := os.RemoveAll(genTestDir3)
require.NoError(t, err)
cmd := exec.Command("jet", "-source=MySQL", "-dbname=dvds", "-host=localhost", "-port=3306",
@ -140,7 +135,7 @@ import (
"github.com/go-jet/jet/v2/mysql"
)
var Actor = newActorTable()
var Actor = newActorTable("dvds", "actor", "")
type ActorTable struct {
mysql.Table
@ -156,13 +151,16 @@ type ActorTable struct {
}
// AS creates new ActorTable with assigned alias
func (a *ActorTable) AS(alias string) ActorTable {
aliasTable := newActorTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a ActorTable) AS(alias string) ActorTable {
return newActorTable(a.SchemaName(), a.TableName(), alias)
}
func newActorTable() ActorTable {
// Schema creates new ActorTable with assigned schema name
func (a ActorTable) FromSchema(schemaName string) ActorTable {
return newActorTable(schemaName, a.TableName(), a.Alias())
}
func newActorTable(schemaName, tableName, alias string) ActorTable {
var (
ActorIDColumn = mysql.IntegerColumn("actor_id")
FirstNameColumn = mysql.StringColumn("first_name")
@ -173,7 +171,7 @@ func newActorTable() ActorTable {
)
return ActorTable{
Table: mysql.NewTable("dvds", "actor", allColumns...),
Table: mysql.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,
@ -223,7 +221,7 @@ import (
"github.com/go-jet/jet/v2/mysql"
)
var ActorInfo = newActorInfoTable()
var ActorInfo = newActorInfoTable("dvds", "actor_info", "")
type ActorInfoTable struct {
mysql.Table
@ -239,13 +237,16 @@ type ActorInfoTable struct {
}
// AS creates new ActorInfoTable with assigned alias
func (a *ActorInfoTable) AS(alias string) ActorInfoTable {
aliasTable := newActorInfoTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a ActorInfoTable) AS(alias string) ActorInfoTable {
return newActorInfoTable(a.SchemaName(), a.TableName(), alias)
}
func newActorInfoTable() ActorInfoTable {
// Schema creates new ActorInfoTable with assigned schema name
func (a ActorInfoTable) FromSchema(schemaName string) ActorInfoTable {
return newActorInfoTable(schemaName, a.TableName(), a.Alias())
}
func newActorInfoTable(schemaName, tableName, alias string) ActorInfoTable {
var (
ActorIDColumn = mysql.IntegerColumn("actor_id")
FirstNameColumn = mysql.StringColumn("first_name")
@ -256,7 +257,7 @@ func newActorInfoTable() ActorInfoTable {
)
return ActorInfoTable{
Table: mysql.NewTable("dvds", "actor_info", allColumns...),
Table: mysql.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,

View file

@ -3,7 +3,6 @@ package mysql
import (
"context"
"database/sql"
"flag"
jetmysql "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/dbconfig"
@ -25,8 +24,7 @@ var source string
const MariaDB = "MariaDB"
func init() {
flag.StringVar(&source, "source", "", "MySQL or MariaDB")
flag.Parse()
source = os.Getenv("MY_SQL_SOURCE")
}
func sourceIsMariaDB() bool {
@ -66,3 +64,9 @@ func requireLogged(t *testing.T, statement postgres.Statement) {
require.Equal(t, loggedSQLArgs, args)
require.Equal(t, loggedDebugSQL, statement.DebugSql())
}
func skipForMariaDB(t *testing.T) {
if sourceIsMariaDB() {
t.SkipNow()
}
}

View file

@ -0,0 +1,123 @@
package mysql
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/model"
. "github.com/go-jet/jet/v2/mysql"
)
func TestRawStatementSelect(t *testing.T) {
stmt := RawStatement(`
SELECT actor.first_name AS "actor.first_name"
FROM dvds.actor
WHERE actor.actor_id = 2`)
testutils.AssertStatementSql(t, stmt, `
SELECT actor.first_name AS "actor.first_name"
FROM dvds.actor
WHERE actor.actor_id = 2;
`)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT actor.first_name AS "actor.first_name"
FROM dvds.actor
WHERE actor.actor_id = 2;
`)
var actor model.Actor
err := stmt.Query(db, &actor)
require.NoError(t, err)
require.Equal(t, actor.FirstName, "NICK")
}
func TestRawStatementSelectWithArguments(t *testing.T) {
stmt := RawStatement(`
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id IN (#actorID1, #actorID2, #actorID3) AND ((#actorID1 / #actorID2) <> (#actorID2 * #actorID3))
ORDER BY actor.actor_id`,
RawArgs{
"#actorID1": int64(1),
"#actorID2": int64(2),
"#actorID3": int64(3),
},
)
testutils.AssertStatementSql(t, stmt, `
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id IN (?, ?, ?) AND ((? / ?) <> (? * ?))
ORDER BY actor.actor_id;
`, int64(1), int64(2), int64(3), int64(1), int64(2), int64(2), int64(3))
testutils.AssertDebugStatementSql(t, stmt, `
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id IN (1, 2, 3) AND ((1 / 2) <> (2 * 3))
ORDER BY actor.actor_id;
`)
var actor []model.Actor
err := stmt.Query(db, &actor)
require.NoError(t, err)
testutils.AssertDeepEqual(t, actor[1], model.Actor{
ActorID: 2,
FirstName: "NICK",
LastName: "WAHLBERG",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 04:34:33", 2),
})
}
func TestRawStatementRows(t *testing.T) {
stmt := RawStatement(`
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
ORDER BY actor.actor_id`)
rows, err := stmt.Rows(context.Background(), db)
require.NoError(t, err)
for rows.Next() {
var actor model.Actor
err := rows.Scan(&actor)
require.NoError(t, err)
require.NotEqual(t, actor.ActorID, int16(0))
require.NotEqual(t, actor.FirstName, "")
require.NotEqual(t, actor.LastName, "")
require.NotEqual(t, actor.LastUpdate, time.Time{})
if actor.ActorID == 54 {
require.Equal(t, actor.ActorID, uint16(54))
require.Equal(t, actor.FirstName, "PENELOPE")
require.Equal(t, actor.LastName, "PINKETT")
require.Equal(t, actor.LastUpdate.Format(time.RFC3339), "2006-02-15T04:34:33Z")
}
}
err = rows.Close()
require.NoError(t, err)
err = rows.Err()
require.NoError(t, err)
requireLogged(t, stmt)
}

View file

@ -1,15 +1,19 @@
package mysql
import (
"context"
"strings"
"testing"
"time"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/enum"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/table"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/view"
"github.com/stretchr/testify/require"
"testing"
"github.com/stretchr/testify/require"
)
func TestSelect_ScanToStruct(t *testing.T) {
@ -744,3 +748,227 @@ LIMIT 3;
require.Equal(t, len(dest), 3)
}
func Test_SchemaRename(t *testing.T) {
Film := Film.FromSchema("dvds2")
Language := Language.FromSchema("dvds2")
stmt := SELECT(
Film.FilmID,
Film.Title,
Language.LanguageID,
Language.Name,
).FROM(
Language.
INNER_JOIN(Film, Film.LanguageID.EQ(Language.LanguageID)),
).WHERE(
Language.LanguageID.EQ(Int(1)),
).ORDER_BY(
Language.LanguageID, Film.FilmID,
).LIMIT(5)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
language.language_id AS "language.language_id",
language.name AS "language.name"
FROM dvds2.language
INNER JOIN dvds2.film ON (film.language_id = language.language_id)
WHERE language.language_id = 1
ORDER BY language.language_id, film.film_id
LIMIT 5;
`)
dest := struct {
model.Language
Films []model.Film
}{}
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest.Films, 5)
require.Equal(t, dest.Films[0].Title, "ACADEMY DINOSAUR")
require.Equal(t, dest.Films[1].Title, "ACE GOLDFINGER")
require.Equal(t, dest.Films[4].Title, "AFRICAN EGG")
}
func TestLateral(t *testing.T) {
skipForMariaDB(t) // MariaDB does not implement LATERAL
languages := LATERAL(
SELECT(
Language.AllColumns,
).FROM(
Language,
).WHERE(
Language.Name.NOT_IN(String("spanish")).
AND(Film.LanguageID.EQ(Language.LanguageID)),
),
).AS("films")
stmt := SELECT(
Film.FilmID,
Film.Title,
languages.AllColumns(),
).FROM(
Film.CROSS_JOIN(languages),
).WHERE(
Film.FilmID.EQ(Int(1)),
).ORDER_BY(
Film.FilmID,
).LIMIT(1)
testutils.AssertDebugStatementSql(t, stmt, strings.Replace(`
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
films.''language.language_id'' AS "language.language_id",
films.''language.name'' AS "language.name",
films.''language.last_update'' AS "language.last_update"
FROM dvds.film
CROSS JOIN LATERAL (
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update"
FROM dvds.language
WHERE (language.name NOT IN ('spanish')) AND (film.language_id = language.language_id)
) AS films
WHERE film.film_id = 1
ORDER BY film.film_id
LIMIT 1;
`, "''", "`", -1))
type FilmLanguage struct {
model.Film
model.Language
}
var dest []FilmLanguage
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest[0].Film.Title, "ACADEMY DINOSAUR")
require.Equal(t, dest[0].Language.Name, "English")
t.Run("implicit cross join", func(t *testing.T) {
stmt2 := SELECT(
Film.FilmID,
Film.Title,
languages.AllColumns(),
).FROM(
Film,
languages,
).WHERE(
Film.FilmID.EQ(Int(1)),
).ORDER_BY(
Film.FilmID,
).LIMIT(1)
testutils.AssertDebugStatementSql(t, stmt2, strings.Replace(`
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
films.''language.language_id'' AS "language.language_id",
films.''language.name'' AS "language.name",
films.''language.last_update'' AS "language.last_update"
FROM dvds.film,
LATERAL (
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update"
FROM dvds.language
WHERE (language.name NOT IN ('spanish')) AND (film.language_id = language.language_id)
) AS films
WHERE film.film_id = 1
ORDER BY film.film_id
LIMIT 1;
`, "''", "`", -1))
var dest2 []FilmLanguage
err2 := stmt2.Query(db, &dest2)
require.NoError(t, err2)
require.Equal(t, dest, dest2)
})
}
func TestRowsScan(t *testing.T) {
stmt := SELECT(
Inventory.AllColumns,
).FROM(
Inventory,
).ORDER_BY(
Inventory.InventoryID.ASC(),
)
rows, err := stmt.Rows(context.Background(), db)
require.NoError(t, err)
for rows.Next() {
var inventory model.Inventory
err = rows.Scan(&inventory)
require.NoError(t, err)
require.NotEqual(t, inventory.InventoryID, uint32(0))
require.NotEqual(t, inventory.FilmID, uint16(0))
require.NotEqual(t, inventory.StoreID, uint16(0))
require.NotEqual(t, inventory.LastUpdate, time.Time{})
if inventory.InventoryID == 2103 {
require.Equal(t, inventory.FilmID, uint16(456))
require.Equal(t, inventory.StoreID, uint8(2))
require.Equal(t, inventory.LastUpdate.Format(time.RFC3339), "2006-02-15T05:09:17Z")
}
}
err = rows.Close()
require.NoError(t, err)
err = rows.Err()
require.NoError(t, err)
requireLogged(t, stmt)
}
func TestScanNumericToNumber(t *testing.T) {
type Number struct {
Int8 int8
UInt8 uint8
Int16 int16
UInt16 uint16
Int32 int32
UInt32 uint32
Int64 int64
UInt64 uint64
Float32 float32
Float64 float64
}
numeric := CAST(Decimal("1234567890.111")).AS_DECIMAL()
stmt := SELECT(
numeric.AS("number.int8"),
numeric.AS("number.uint8"),
numeric.AS("number.int16"),
numeric.AS("number.uint16"),
numeric.AS("number.int32"),
numeric.AS("number.uint32"),
numeric.AS("number.int64"),
numeric.AS("number.uint64"),
numeric.AS("number.float32"),
numeric.AS("number.float64"),
)
var number Number
err := stmt.Query(db, &number)
require.NoError(t, err)
require.Equal(t, number.Int8, int8(-46)) // overflow
require.Equal(t, number.UInt8, uint8(210)) // overflow
require.Equal(t, number.Int16, int16(722)) // overflow
require.Equal(t, number.UInt16, uint16(722)) // overflow
require.Equal(t, number.Int32, int32(1234567890))
require.Equal(t, number.UInt32, uint32(1234567890))
require.Equal(t, number.Int64, int64(1234567890))
require.Equal(t, number.UInt64, uint64(1234567890))
require.Equal(t, number.Float32, float32(1.234568e+09))
require.Equal(t, number.Float64, float64(1.23456789e+09))
}

View file

@ -2,7 +2,6 @@ package mysql
import (
"context"
"fmt"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/table"
@ -193,7 +192,7 @@ SET url = 'http://www.duckduckgo.com',
description = NULL
WHERE link.id = 201;
`
fmt.Println(stmt.DebugSql())
//fmt.Println(stmt.DebugSql())
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
testutils.AssertExec(t, stmt, db)

View file

@ -1,20 +1,24 @@
package postgres
import (
"github.com/stretchr/testify/require"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/google/uuid"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/view"
"github.com/go-jet/jet/v2/tests/testdata/results/common"
"github.com/google/uuid"
)
func TestAllTypesSelect(t *testing.T) {
skipForPgxDriver(t) // pgx driver returns time with time zone as string
dest := []model.AllTypes{}
err := AllTypes.SELECT(AllTypes.AllColumns).Query(db, &dest)
@ -25,6 +29,8 @@ func TestAllTypesSelect(t *testing.T) {
}
func TestAllTypesViewSelect(t *testing.T) {
skipForPgxDriver(t) // pgx driver returns time with time zone as string
type AllTypesView model.AllTypes
dest := []AllTypesView{}
@ -37,6 +43,8 @@ func TestAllTypesViewSelect(t *testing.T) {
}
func TestAllTypesInsertModel(t *testing.T) {
skipForPgxDriver(t) // pgx driver does not handle well time with time zone
query := AllTypes.INSERT(AllTypes.AllColumns).
MODEL(allTypesRow0).
MODEL(&allTypesRow1).
@ -52,6 +60,8 @@ func TestAllTypesInsertModel(t *testing.T) {
}
func TestAllTypesInsertQuery(t *testing.T) {
skipForPgxDriver(t) // pgx driver does not handle well time with time zone
query := AllTypes.INSERT(AllTypes.AllColumns).
QUERY(
AllTypes.
@ -70,6 +80,7 @@ func TestAllTypesInsertQuery(t *testing.T) {
}
func TestAllTypesFromSubQuery(t *testing.T) {
skipForPgxDriver(t)
subQuery := SELECT(AllTypes.AllColumns).
FROM(AllTypes).
@ -221,12 +232,16 @@ func TestExpressionOperators(t *testing.T) {
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
Raw("CURRENT_USER").AS("result.raw"),
Raw("#1 + COALESCE(all_types.small_int_ptr, 0) + #2", RawArgs{"#1": 78, "#2": 56}).AS("result.raw_arg"),
Raw("#1 + all_types.integer + #2 + #1 + #3 + #4",
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}).AS("result.raw_arg2"),
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
AllTypes.SmallIntPtr.NOT_IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.not_in_select"),
).LIMIT(2)
//fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, `
SELECT all_types.integer IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
@ -235,14 +250,17 @@ SELECT all_types.integer IS NULL AS "result.is_null",
SELECT all_types.integer AS "all_types.integer"
FROM test_sample.all_types
))) AS "result.in_select",
(all_types.small_int_ptr NOT IN ($3, $4, NULL)) AS "result.not_in",
(CURRENT_USER) AS "result.raw",
($3 + COALESCE(all_types.small_int_ptr, 0) + $4) AS "result.raw_arg",
($5 + all_types.integer + $6 + $5 + $7 + $8) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN ($9, $10, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN ((
SELECT all_types.integer AS "all_types.integer"
FROM test_sample.all_types
))) AS "result.not_in_select"
FROM test_sample.all_types
LIMIT $5;
`, int64(11), int64(22), int64(11), int64(22), int64(2))
LIMIT $11;
`, int64(11), int64(22), 78, 56, 11, 22, 33, 44, int64(11), int64(22), int64(2))
var dest []struct {
common.ExpressionTestResult `alias:"result.*"`
@ -261,6 +279,9 @@ LIMIT $5;
"IsNotNull": true,
"In": false,
"InSelect": false,
"Raw": "jet",
"RawArg": 148,
"RawArg2": 421,
"NotIn": null,
"NotInSelect": true
},
@ -269,6 +290,9 @@ LIMIT $5;
"IsNotNull": false,
"In": null,
"InSelect": null,
"Raw": "jet",
"RawArg": 134,
"RawArg2": 421,
"NotIn": null,
"NotInSelect": null
}
@ -278,6 +302,8 @@ LIMIT $5;
func TestExpressionCast(t *testing.T) {
skipForPgxDriver(t) // for some reason, pgx driver, 150:char(12) returns as int value
query := AllTypes.SELECT(
CAST(Int(150)).AS_CHAR(12).AS("char12"),
CAST(String("TRUE")).AS_BOOL(),
@ -323,6 +349,8 @@ func TestExpressionCast(t *testing.T) {
}
func TestStringOperators(t *testing.T) {
skipForPgxDriver(t) // pgx driver returns text column as int value
query := AllTypes.SELECT(
AllTypes.Text.EQ(AllTypes.Char),
AllTypes.Text.EQ(String("Text")),
@ -838,6 +866,7 @@ func TestInterval(t *testing.T) {
}
func TestSubQueryColumnReference(t *testing.T) {
skipForPgxDriver(t) // pgx driver returns time with time zone as string value
type expected struct {
sql string
@ -1015,6 +1044,7 @@ FROM`
}
func TestTimeLiterals(t *testing.T) {
skipForPgxDriver(t) // pgx driver returns time with time zone as string
loc, err := time.LoadLocation("Europe/Berlin")
require.NoError(t, err)

View file

@ -2,7 +2,6 @@ package postgres
import (
"context"
"fmt"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/chinook/model"
@ -17,7 +16,7 @@ func TestSelect(t *testing.T) {
SELECT(Album.AllColumns).
ORDER_BY(Album.AlbumId.ASC())
fmt.Println(stmt.DebugSql())
//fmt.Println(stmt.DebugSql())
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "Album"."AlbumId" AS "Album.AlbumId",
@ -330,8 +329,71 @@ ORDER BY "first10Artist"."Artist.ArtistId";
err := stmt.Query(db, &dest)
require.NoError(t, err)
}
//spew.Dump(dest)
func Test_SchemaRename(t *testing.T) {
Artist2 := Artist.FromSchema("chinook2")
Album2 := Album.FromSchema("chinook2")
first10Artist := Artist2.
SELECT(Artist2.AllColumns).
ORDER_BY(Artist2.ArtistId).
LIMIT(10).
AsTable("first10Artist")
artistID := Artist2.ArtistId.From(first10Artist)
first10Albums := Album2.
SELECT(Album2.AllColumns).
ORDER_BY(Album2.AlbumId).
LIMIT(10).
AsTable("first10Albums")
albumArtistID := Album2.ArtistId.From(first10Albums)
stmt := SELECT(first10Artist.AllColumns(), first10Albums.AllColumns()).
FROM(first10Artist.
INNER_JOIN(first10Albums, artistID.EQ(albumArtistID))).
ORDER_BY(artistID)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "first10Artist"."Artist.ArtistId" AS "Artist.ArtistId",
"first10Artist"."Artist.Name" AS "Artist.Name",
"first10Albums"."Album.AlbumId" AS "Album.AlbumId",
"first10Albums"."Album.Title" AS "Album.Title",
"first10Albums"."Album.ArtistId" AS "Album.ArtistId"
FROM (
SELECT "Artist"."ArtistId" AS "Artist.ArtistId",
"Artist"."Name" AS "Artist.Name"
FROM chinook2."Artist"
ORDER BY "Artist"."ArtistId"
LIMIT 10
) AS "first10Artist"
INNER JOIN (
SELECT "Album"."AlbumId" AS "Album.AlbumId",
"Album"."Title" AS "Album.Title",
"Album"."ArtistId" AS "Album.ArtistId"
FROM chinook2."Album"
ORDER BY "Album"."AlbumId"
LIMIT 10
) AS "first10Albums" ON ("first10Artist"."Artist.ArtistId" = "first10Albums"."Album.ArtistId")
ORDER BY "first10Artist"."Artist.ArtistId";
`)
var dest []struct {
model.Artist
Album []model.Album
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 2)
require.Equal(t, *dest[0].Artist.Name, "Apocalyptica")
require.Len(t, dest[0].Album, 1)
require.Equal(t, dest[0].Album[0].Title, "Plays Metallica By Four Cellos")
}
var album1 = model.Album{

View file

@ -46,12 +46,7 @@ func TestGeneratedModel(t *testing.T) {
const genTestDir2 = "./.gentestdata2"
func TestCmdGenerator(t *testing.T) {
goInstallJet := exec.Command("sh", "-c", "cd $GOPATH/src/ && GO111MODULE=off go get github.com/go-jet/jet/cmd/jet")
goInstallJet.Stderr = os.Stderr
err := goInstallJet.Run()
require.NoError(t, err)
err = os.RemoveAll(genTestDir2)
err := os.RemoveAll(genTestDir2)
require.NoError(t, err)
cmd := exec.Command("jet", "-source=PostgreSQL", "-dbname=jetdb", "-host=localhost", "-port=5432",
@ -173,7 +168,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var Actor = newActorTable()
var Actor = newActorTable("dvds", "actor", "")
type actorTable struct {
postgres.Table
@ -195,20 +190,23 @@ type ActorTable struct {
}
// AS creates new ActorTable with assigned alias
func (a *ActorTable) AS(alias string) *ActorTable {
aliasTable := newActorTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a ActorTable) AS(alias string) *ActorTable {
return newActorTable(a.SchemaName(), a.TableName(), alias)
}
func newActorTable() *ActorTable {
// Schema creates new ActorTable with assigned schema name
func (a ActorTable) FromSchema(schemaName string) *ActorTable {
return newActorTable(schemaName, a.TableName(), a.Alias())
}
func newActorTable(schemaName, tableName, alias string) *ActorTable {
return &ActorTable{
actorTable: newActorTableImpl("dvds", "actor"),
EXCLUDED: newActorTableImpl("", "excluded"),
actorTable: newActorTableImpl(schemaName, tableName, alias),
EXCLUDED: newActorTableImpl("", "excluded", ""),
}
}
func newActorTableImpl(schemaName, tableName string) actorTable {
func newActorTableImpl(schemaName, tableName, alias string) actorTable {
var (
ActorIDColumn = postgres.IntegerColumn("actor_id")
FirstNameColumn = postgres.StringColumn("first_name")
@ -219,7 +217,7 @@ func newActorTableImpl(schemaName, tableName string) actorTable {
)
return actorTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,
@ -269,7 +267,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var ActorInfo = newActorInfoTable()
var ActorInfo = newActorInfoTable("dvds", "actor_info", "")
type actorInfoTable struct {
postgres.Table
@ -291,20 +289,23 @@ type ActorInfoTable struct {
}
// AS creates new ActorInfoTable with assigned alias
func (a *ActorInfoTable) AS(alias string) *ActorInfoTable {
aliasTable := newActorInfoTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a ActorInfoTable) AS(alias string) *ActorInfoTable {
return newActorInfoTable(a.SchemaName(), a.TableName(), alias)
}
func newActorInfoTable() *ActorInfoTable {
// Schema creates new ActorInfoTable with assigned schema name
func (a ActorInfoTable) FromSchema(schemaName string) *ActorInfoTable {
return newActorInfoTable(schemaName, a.TableName(), a.Alias())
}
func newActorInfoTable(schemaName, tableName, alias string) *ActorInfoTable {
return &ActorInfoTable{
actorInfoTable: newActorInfoTableImpl("dvds", "actor_info"),
EXCLUDED: newActorInfoTableImpl("", "excluded"),
actorInfoTable: newActorInfoTableImpl(schemaName, tableName, alias),
EXCLUDED: newActorInfoTableImpl("", "excluded", ""),
}
}
func newActorInfoTableImpl(schemaName, tableName string) actorInfoTable {
func newActorInfoTableImpl(schemaName, tableName, alias string) actorInfoTable {
var (
ActorIDColumn = postgres.IntegerColumn("actor_id")
FirstNameColumn = postgres.StringColumn("first_name")
@ -315,7 +316,7 @@ func newActorInfoTableImpl(schemaName, tableName string) actorInfoTable {
)
return actorInfoTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ActorID: ActorIDColumn,
@ -345,7 +346,7 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
require.NoError(t, err)
testutils.AssertFileNamesEqual(t, modelFiles, "all_types.go", "all_types_view.go", "employee.go", "link.go",
"mood.go", "person.go", "person_phone.go", "weird_names_table.go", "level.go", "user.go")
"mood.go", "person.go", "person_phone.go", "weird_names_table.go", "level.go", "user.go", "floats.go")
testutils.AssertFileContent(t, modelDir+"all_types.go", allTypesModelContent)
@ -353,7 +354,7 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
require.NoError(t, err)
testutils.AssertFileNamesEqual(t, tableFiles, "all_types.go", "employee.go", "link.go",
"person.go", "person_phone.go", "weird_names_table.go", "user.go")
"person.go", "person_phone.go", "weird_names_table.go", "user.go", "floats.go")
testutils.AssertFileContent(t, tableDir+"all_types.go", allTypesTableContent)
}
@ -502,7 +503,7 @@ import (
"github.com/go-jet/jet/v2/postgres"
)
var AllTypes = newAllTypesTable()
var AllTypes = newAllTypesTable("test_sample", "all_types", "")
type allTypesTable struct {
postgres.Table
@ -581,20 +582,23 @@ type AllTypesTable struct {
}
// AS creates new AllTypesTable with assigned alias
func (a *AllTypesTable) AS(alias string) *AllTypesTable {
aliasTable := newAllTypesTable()
aliasTable.Table.AS(alias)
return aliasTable
func (a AllTypesTable) AS(alias string) *AllTypesTable {
return newAllTypesTable(a.SchemaName(), a.TableName(), alias)
}
func newAllTypesTable() *AllTypesTable {
// Schema creates new AllTypesTable with assigned schema name
func (a AllTypesTable) FromSchema(schemaName string) *AllTypesTable {
return newAllTypesTable(schemaName, a.TableName(), a.Alias())
}
func newAllTypesTable(schemaName, tableName, alias string) *AllTypesTable {
return &AllTypesTable{
allTypesTable: newAllTypesTableImpl("test_sample", "all_types"),
EXCLUDED: newAllTypesTableImpl("", "excluded"),
allTypesTable: newAllTypesTableImpl(schemaName, tableName, alias),
EXCLUDED: newAllTypesTableImpl("", "excluded", ""),
}
}
func newAllTypesTableImpl(schemaName, tableName string) allTypesTable {
func newAllTypesTableImpl(schemaName, tableName, alias string) allTypesTable {
var (
SmallIntPtrColumn = postgres.IntegerColumn("small_int_ptr")
SmallIntColumn = postgres.IntegerColumn("small_int")
@ -662,7 +666,7 @@ func newAllTypesTableImpl(schemaName, tableName string) allTypesTable {
)
return allTypesTable{
Table: postgres.NewTable(schemaName, tableName, allColumns...),
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
SmallIntPtr: SmallIntPtrColumn,

View file

@ -3,17 +3,23 @@ package postgres
import (
"context"
"database/sql"
"github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/dbconfig"
_ "github.com/lib/pq"
"github.com/pkg/profile"
"github.com/stretchr/testify/require"
"fmt"
"math/rand"
"os"
"os/exec"
"strings"
"testing"
"time"
"github.com/jackc/pgx/v4/stdlib"
"github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/dbconfig"
_ "github.com/lib/pq"
"github.com/pkg/profile"
"github.com/stretchr/testify/require"
_ "github.com/jackc/pgx/v4/stdlib"
)
var db *sql.DB
@ -25,16 +31,23 @@ func TestMain(m *testing.M) {
setTestRoot()
var err error
db, err = sql.Open("postgres", dbconfig.PostgresConnectString)
if err != nil {
panic("Failed to connect to test db")
for _, driverName := range []string{"postgres", "pgx"} {
func() {
var err error
db, err = sql.Open(driverName, dbconfig.PostgresConnectString)
if err != nil {
fmt.Println(err.Error())
panic("Failed to connect to test db")
}
defer db.Close()
ret := m.Run()
if ret != 0 {
os.Exit(ret)
}
}()
}
defer db.Close()
ret := m.Run()
os.Exit(ret)
}
func setTestRoot() {
@ -64,3 +77,10 @@ func requireLogged(t *testing.T, statement postgres.Statement) {
require.Equal(t, loggedSQLArgs, args)
require.Equal(t, loggedDebugSQL, statement.DebugSql())
}
func skipForPgxDriver(t *testing.T) {
switch db.Driver().(type) {
case *stdlib.Driver:
t.SkipNow()
}
}

View file

@ -0,0 +1,179 @@
package postgres
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
model2 "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/model"
. "github.com/go-jet/jet/v2/postgres"
)
func TestRawStatementSelect(t *testing.T) {
stmt := RawStatement(`
SELECT actor.first_name AS "actor.first_name"
FROM dvds.actor
WHERE actor.actor_id = 2`)
testutils.AssertStatementSql(t, stmt, `
SELECT actor.first_name AS "actor.first_name"
FROM dvds.actor
WHERE actor.actor_id = 2;
`)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT actor.first_name AS "actor.first_name"
FROM dvds.actor
WHERE actor.actor_id = 2;
`)
var actor model.Actor
err := stmt.Query(db, &actor)
require.NoError(t, err)
require.Equal(t, actor.FirstName, "Nick")
}
func TestRawStatementSelectWithArguments(t *testing.T) {
stmt := RawStatement(`
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id IN (#actorID1, #actorID2, #actorID3) AND ((#actorID1 / #actorID2) <> (#actorID2 * #actorID3))
ORDER BY actor.actor_id`,
RawArgs{
"#actorID1": int64(1),
"#actorID2": int64(2),
"#actorID3": int64(3),
},
)
testutils.AssertStatementSql(t, stmt, `
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id IN ($1, $2, $3) AND (($1 / $2) <> ($2 * $3))
ORDER BY actor.actor_id;
`, int64(1), int64(2), int64(3))
testutils.AssertDebugStatementSql(t, stmt, `
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id IN (1, 2, 3) AND ((1 / 2) <> (2 * 3))
ORDER BY actor.actor_id;
`)
var actor []model.Actor
err := stmt.Query(db, &actor)
require.NoError(t, err)
testutils.AssertDeepEqual(t, actor[1], model.Actor{
ActorID: 2,
FirstName: "Nick",
LastName: "Wahlberg",
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:47:57.62", 2),
})
}
func TestRawInsert(t *testing.T) {
cleanUpLinkTable(t)
stmt := RawStatement(`
INSERT INTO test_sample.link (id, url, name, description)
VALUES (@id1, @url1, @name1, DEFAULT),
(200, @url1, @name1, NULL),
(@id2, @url2, @name2, DEFAULT),
(@id3, @url3, @name3, NULL)
RETURNING link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description"`,
RawArgs{
"@id1": 100, "@url1": "http://www.postgresqltutorial.com", "@name1": "PostgreSQL Tutorial",
"@id2": 101, "@url2": "http://www.google.com", "@name2": "Google",
"@id3": 102, "@url3": "http://www.yahoo.com", "@name3": "Yahoo",
})
testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.link (id, url, name, description)
VALUES ($1, $2, $3, DEFAULT),
(200, $2, $3, NULL),
($4, $5, $6, DEFAULT),
($7, $8, $9, NULL)
RETURNING link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description";
`, 100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
101, "http://www.google.com", "Google",
102, "http://www.yahoo.com", "Yahoo")
testutils.AssertDebugStatementSql(t, stmt, `
INSERT INTO test_sample.link (id, url, name, description)
VALUES (100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
(200, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', NULL),
(101, 'http://www.google.com', 'Google', DEFAULT),
(102, 'http://www.yahoo.com', 'Yahoo', NULL)
RETURNING link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description";
`)
var links []model2.Link
err := stmt.Query(db, &links)
require.NoError(t, err)
require.Len(t, links, 4)
require.Equal(t, links[0].ID, int32(100))
require.Equal(t, links[1].URL, "http://www.postgresqltutorial.com")
require.Equal(t, links[2].Name, "Google")
require.Nil(t, links[2].Description)
}
func TestRawStatementRows(t *testing.T) {
stmt := RawStatement(`
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
ORDER BY actor.actor_id`)
rows, err := stmt.Rows(context.Background(), db)
require.NoError(t, err)
for rows.Next() {
var actor model.Actor
err := rows.Scan(&actor)
require.NoError(t, err)
require.NotEqual(t, actor.ActorID, int32(0))
require.NotEqual(t, actor.FirstName, "")
require.NotEqual(t, actor.LastName, "")
require.NotEqual(t, actor.LastUpdate, time.Time{})
if actor.ActorID == 54 {
require.Equal(t, actor.ActorID, int32(54))
require.Equal(t, actor.FirstName, "Penelope")
require.Equal(t, actor.LastName, "Pinkett")
require.Equal(t, actor.LastUpdate.Format(time.RFC3339), "2013-05-26T14:47:57Z")
}
}
err = rows.Close()
require.NoError(t, err)
err = rows.Err()
require.NoError(t, err)
requireLogged(t, stmt)
}

View file

@ -1,19 +1,26 @@
package postgres
import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"testing"
"github.com/shopspring/decimal"
)
func TestUUIDType(t *testing.T) {
id := uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
query := AllTypes.
SELECT(AllTypes.UUID, AllTypes.UUIDPtr).
WHERE(AllTypes.UUID.EQ(String("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")))
WHERE(AllTypes.UUID.EQ(UUID(id)))
testutils.AssertDebugStatementSql(t, query, `
SELECT all_types.uuid AS "all_types.uuid",
@ -31,6 +38,110 @@ WHERE all_types.uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';
requireLogged(t, query)
}
func TestExactDecimals(t *testing.T) {
type floats struct {
model.Floats
Numeric decimal.Decimal
NumericPtr decimal.Decimal
Decimal decimal.Decimal
DecimalPtr decimal.Decimal
}
t.Run("should query decimal", func(t *testing.T) {
query := SELECT(
Floats.AllColumns,
).FROM(
Floats,
).WHERE(Floats.Decimal.EQ(Decimal("1.11111111111111111111")))
var result floats
err := query.Query(db, &result)
require.NoError(t, err)
require.Equal(t, "1.11111111111111111111", result.Decimal.String())
require.Equal(t, "0", result.DecimalPtr.String()) // NULL
require.Equal(t, "2.22222222222222222222", result.Numeric.String())
require.Equal(t, "0", result.NumericPtr.String()) // NULL
require.Equal(t, 1.1111111111111112, result.Floats.Decimal) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.DecimalPtr)
require.Equal(t, 2.2222222222222223, result.Floats.Numeric) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.NumericPtr)
// floating point
require.Equal(t, float32(3.3333333), result.Floats.Real) // precision loss
require.Equal(t, (*float32)(nil), result.Floats.RealPtr)
require.Equal(t, 4.444444444444445, result.Floats.Double) // precision loss
require.Equal(t, (*float64)(nil), result.Floats.DoublePtr)
})
t.Run("should insert decimal", func(t *testing.T) {
insertQuery := Floats.INSERT(
Floats.AllColumns,
).MODEL(
floats{
Floats: model.Floats{
// overwritten by wrapped(floats) scope
Numeric: 0.1,
NumericPtr: testutils.Float64Ptr(0.1),
Decimal: 0.1,
DecimalPtr: testutils.Float64Ptr(0.1),
// not overwritten
Real: 0.4,
RealPtr: testutils.Float32Ptr(0.44),
Double: 0.3,
DoublePtr: testutils.Float64Ptr(0.33),
},
Numeric: decimal.RequireFromString("0.1234567890123456789"),
NumericPtr: decimal.RequireFromString("1.1111111111111111111"),
Decimal: decimal.RequireFromString("2.2222222222222222222"),
DecimalPtr: decimal.RequireFromString("3.3333333333333333333"),
},
).RETURNING(
Floats.AllColumns,
)
testutils.AssertDebugStatementSql(t, insertQuery, `
INSERT INTO test_sample.floats (decimal_ptr, decimal, numeric_ptr, numeric, real_ptr, real, double_ptr, double)
VALUES ('3.3333333333333333333', '2.2222222222222222222', '1.1111111111111111111', '0.1234567890123456789', 0.4399999976158142, 0.4000000059604645, 0.33, 0.3)
RETURNING floats.decimal_ptr AS "floats.decimal_ptr",
floats.decimal AS "floats.decimal",
floats.numeric_ptr AS "floats.numeric_ptr",
floats.numeric AS "floats.numeric",
floats.real_ptr AS "floats.real_ptr",
floats.real AS "floats.real",
floats.double_ptr AS "floats.double_ptr",
floats.double AS "floats.double";
`)
var result floats
err := insertQuery.Query(db, &result)
require.NoError(t, err)
// exact decimal
require.Equal(t, "0.1234567890123456789", result.Numeric.String())
require.Equal(t, "1.1111111111111111111", result.NumericPtr.String())
require.Equal(t, "2.2222222222222222222", result.Decimal.String())
require.Equal(t, "3.3333333333333333333", result.DecimalPtr.String())
// precision loss
require.Equal(t, 0.12345678901234568, result.Floats.Numeric)
require.Equal(t, 1.1111111111111112, *result.Floats.NumericPtr)
require.Equal(t, 2.2222222222222223, result.Floats.Decimal)
require.Equal(t, 3.3333333333333335, *result.Floats.DecimalPtr)
// floating points numbers
require.Equal(t, float32(0.4), result.Floats.Real)
require.Equal(t, float32(0.44), *result.Floats.RealPtr)
require.Equal(t, 0.3, result.Floats.Double)
require.Equal(t, 0.33, *result.Floats.DoublePtr)
})
}
func TestUUIDComplex(t *testing.T) {
query := Person.INNER_JOIN(PersonPhone, PersonPhone.PersonID.EQ(Person.PersonID)).
SELECT(Person.AllColumns, PersonPhone.AllColumns).
@ -364,7 +475,7 @@ FROM test_sample."User";
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.PrintJson(dest)
//testutils.PrintJson(dest)
testutils.AssertJSON(t, dest, `
[
@ -386,3 +497,54 @@ FROM test_sample."User";
]
`)
}
func TestBytea(t *testing.T) {
byteArrHex := "\\x48656c6c6f20476f7068657221"
byteArrBin := []byte("\x48\x65\x6c\x6c\x6f\x20\x47\x6f\x70\x68\x65\x72\x21")
insertStmt := AllTypes.INSERT(AllTypes.Bytea, AllTypes.ByteaPtr).
VALUES(byteArrHex, byteArrBin).
RETURNING(AllTypes.Bytea, AllTypes.ByteaPtr)
testutils.AssertStatementSql(t, insertStmt, `
INSERT INTO test_sample.all_types (bytea, bytea_ptr)
VALUES ($1, $2)
RETURNING all_types.bytea AS "all_types.bytea",
all_types.bytea_ptr AS "all_types.bytea_ptr";
`, byteArrHex, byteArrBin)
var inserted model.AllTypes
err := insertStmt.Query(db, &inserted)
require.NoError(t, err)
require.Equal(t, string(*inserted.ByteaPtr), "Hello Gopher!")
// It is not possible to initiate bytea column using hex format '\xDEADBEEF' with pq driver.
// pq driver always encodes parameter string if destination column is of type bytea.
// Probably pq driver error.
// require.Equal(t, string(inserted.Bytea), "Hello Gopher!")
stmt := SELECT(
AllTypes.Bytea,
AllTypes.ByteaPtr,
).FROM(
AllTypes,
).WHERE(
AllTypes.ByteaPtr.EQ(Bytea(byteArrBin)),
)
testutils.AssertStatementSql(t, stmt, `
SELECT all_types.bytea AS "all_types.bytea",
all_types.bytea_ptr AS "all_types.bytea_ptr"
FROM test_sample.all_types
WHERE all_types.bytea_ptr = $1::bytea;
`, byteArrBin)
var dest model.AllTypes
err = stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, string(*dest.ByteaPtr), "Hello Gopher!")
// Probably pq driver error.
// require.Equal(t, string(dest.Bytea), "Hello Gopher!")
}

View file

@ -1,15 +1,18 @@
package postgres
import (
"fmt"
"context"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/qrm"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/table"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"testing"
)
var oneInventoryQuery = Inventory.
@ -93,7 +96,7 @@ func TestScanToStruct(t *testing.T) {
SELECT(Inventory.AllColumns).
ORDER_BY(Inventory.InventoryID)
fmt.Println(query.DebugSql())
//fmt.Println(query.DebugSql())
t.Run("one struct", func(t *testing.T) {
dest := model.Inventory{}
@ -723,6 +726,89 @@ func TestStructScanAllNull(t *testing.T) {
}{})
}
func TestRowsScan(t *testing.T) {
stmt := SELECT(
Inventory.AllColumns,
).FROM(
Inventory,
).ORDER_BY(
Inventory.InventoryID.ASC(),
)
rows, err := stmt.Rows(context.Background(), db)
require.NoError(t, err)
for rows.Next() {
var inventory model.Inventory
err = rows.Scan(&inventory)
require.NoError(t, err)
require.NotEqual(t, inventory.InventoryID, int32(0))
require.NotEqual(t, inventory.FilmID, int16(0))
require.NotEqual(t, inventory.StoreID, int16(0))
require.NotEqual(t, inventory.LastUpdate, time.Time{})
if inventory.InventoryID == 2103 {
require.Equal(t, inventory.FilmID, int16(456))
require.Equal(t, inventory.StoreID, int16(2))
require.Equal(t, inventory.LastUpdate.Format(time.RFC3339), "2006-02-15T10:09:17Z")
}
}
err = rows.Close()
require.NoError(t, err)
err = rows.Err()
require.NoError(t, err)
requireLogged(t, stmt)
}
func TestScanNumericToNumber(t *testing.T) {
type Number struct {
Int8 int8
UInt8 uint8
Int16 int16
UInt16 uint16
Int32 int32
UInt32 uint32
Int64 int64
UInt64 uint64
Float32 float32
Float64 float64
}
numeric := CAST(Decimal("1234567890.111")).AS_NUMERIC()
stmt := SELECT(
numeric.AS("number.int8"),
numeric.AS("number.uint8"),
numeric.AS("number.int16"),
numeric.AS("number.uint16"),
numeric.AS("number.int32"),
numeric.AS("number.uint32"),
numeric.AS("number.int64"),
numeric.AS("number.uint64"),
numeric.AS("number.float32"),
numeric.AS("number.float64"),
)
var number Number
err := stmt.Query(db, &number)
require.NoError(t, err)
require.Equal(t, number.Int8, int8(-46)) // overflow
require.Equal(t, number.UInt8, uint8(210)) // overflow
require.Equal(t, number.Int16, int16(722)) // overflow
require.Equal(t, number.UInt16, uint16(722)) // overflow
require.Equal(t, number.Int32, int32(1234567890))
require.Equal(t, number.UInt32, uint32(1234567890))
require.Equal(t, number.Int64, int64(1234567890))
require.Equal(t, number.UInt64, uint64(1234567890))
require.Equal(t, number.Float32, float32(1.234568e+09))
require.Equal(t, number.Float64, float64(1.234567890111e+09))
}
var address256 = model.Address{
AddressID: 256,
Address: "1497 Yuzhou Drive",

View file

@ -1,16 +1,17 @@
package postgres
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/enum"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/table"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/view"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func TestSelect_ScanToStruct(t *testing.T) {
@ -1255,7 +1256,7 @@ OFFSET 20;
LIMIT(10).
OFFSET(20)
fmt.Println(query.DebugSql())
//fmt.Println(query.DebugSql())
testutils.AssertDebugStatementSql(t, query, expectedQuery, float64(100), float64(200), int64(10), int64(20))
@ -1788,7 +1789,7 @@ func TestJoinViewWithTable(t *testing.T) {
Rentals []model.Rental
}
fmt.Println(query.DebugSql())
//fmt.Println(query.DebugSql())
err := query.Query(db, &dest)
require.NoError(t, err)
@ -1894,3 +1895,100 @@ WHERE ($1 AND (customer.customer_id = $2)) AND (customer.activebool = $3);
require.Len(t, dest, 1)
testutils.AssertDeepEqual(t, dest[0], customer0)
}
func TestLateral(t *testing.T) {
languages := LATERAL(
SELECT(
Language.AllColumns,
).FROM(
Language,
).WHERE(
Language.Name.NOT_IN(String("spanish")).
AND(Film.LanguageID.EQ(Language.LanguageID)),
),
).AS("films")
stmt := SELECT(
Film.FilmID,
Film.Title,
languages.AllColumns(),
).FROM(
Film.CROSS_JOIN(languages),
).WHERE(
Film.FilmID.EQ(Int(1)),
).ORDER_BY(
Film.FilmID,
).LIMIT(1)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
films."language.language_id" AS "language.language_id",
films."language.name" AS "language.name",
films."language.last_update" AS "language.last_update"
FROM dvds.film
CROSS JOIN LATERAL (
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update"
FROM dvds.language
WHERE (language.name NOT IN ('spanish')) AND (film.language_id = language.language_id)
) AS films
WHERE film.film_id = 1
ORDER BY film.film_id
LIMIT 1;
`)
type FilmLanguage struct {
model.Film
model.Language
}
var dest []FilmLanguage
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest[0].Film.Title, "Academy Dinosaur")
require.Equal(t, dest[0].Language.Name, "English ")
t.Run("implicit cross join", func(t *testing.T) {
stmt2 := SELECT(
Film.FilmID,
Film.Title,
languages.AllColumns(),
).FROM(
Film,
languages,
).WHERE(
Film.FilmID.EQ(Int(1)),
).ORDER_BY(
Film.FilmID,
).LIMIT(1)
testutils.AssertDebugStatementSql(t, stmt2, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
films."language.language_id" AS "language.language_id",
films."language.name" AS "language.name",
films."language.last_update" AS "language.last_update"
FROM dvds.film,
LATERAL (
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update"
FROM dvds.language
WHERE (language.name NOT IN ('spanish')) AND (film.language_id = language.language_id)
) AS films
WHERE film.film_id = 1
ORDER BY film.film_id
LIMIT 1;
`)
var dest2 []FilmLanguage
err2 := stmt2.Query(db, &dest2)
require.NoError(t, err2)
require.Equal(t, dest, dest2)
})
}

@ -1 +1 @@
Subproject commit ed53a505eb738d1be457877eee251f9ba0418df1
Subproject commit a6c1975a167645f913496131ae81d4cabc070046