Update wiki pages.
This commit is contained in:
parent
fafe0866ea
commit
67e6fca0ce
13 changed files with 350 additions and 51 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
[](https://circleci.com/gh/go-jet/jet/tree/develop)
|
[](https://circleci.com/gh/go-jet/jet/tree/develop)
|
||||||
|
|
||||||
Jet is Go SQL Builder for PostgreSQL(support for MySql and OracleSql will be added later).
|
Jet is Go SQL Builder for PostgreSQL(support for MySql and OracleSql will be added later).
|
||||||
Jet enables writing type safe SQL queries in Go, and ability to easily convert database query result to desired arbitrary structure.
|
Jet enables writing type safe SQL queries in Go, and has ability to convert database query result to desired arbitrary structure.
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
- [Getting Started](#getting-started)
|
- [Getting Started](#getting-started)
|
||||||
|
|
|
||||||
|
|
@ -69,21 +69,21 @@ func (d *deleteStatementImpl) Sql() (query string, args []interface{}, err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) DebugSql() (query string, err error) {
|
func (d *deleteStatementImpl) DebugSql() (query string, err error) {
|
||||||
return DebugSql(d)
|
return debugSql(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) Query(db execution.DB, destination interface{}) error {
|
func (d *deleteStatementImpl) Query(db execution.DB, destination interface{}) error {
|
||||||
return Query(d, db, destination)
|
return query(d, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (d *deleteStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return QueryContext(d, db, context, destination)
|
return queryContext(d, db, context, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (d *deleteStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
return Exec(d, db)
|
return exec(d, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
func (d *deleteStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
return ExecContext(d, db, context)
|
return execContext(d, db, context)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func (i *insertStatementImpl) QUERY(selectStatement SelectStatement) InsertState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) DebugSql() (query string, err error) {
|
func (i *insertStatementImpl) DebugSql() (query string, err error) {
|
||||||
return DebugSql(i)
|
return debugSql(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error) {
|
func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error) {
|
||||||
|
|
@ -147,17 +147,17 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) Query(db execution.DB, destination interface{}) error {
|
func (i *insertStatementImpl) Query(db execution.DB, destination interface{}) error {
|
||||||
return Query(i, db, destination)
|
return query(i, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (i *insertStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return QueryContext(i, db, context, destination)
|
return queryContext(i, db, context, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (i *insertStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
return Exec(i, db)
|
return exec(i, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
func (i *insertStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
return ExecContext(i, db, context)
|
return execContext(i, db, context)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (l *lockStatementImpl) NOWAIT() LockStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) DebugSql() (query string, err error) {
|
func (l *lockStatementImpl) DebugSql() (query string, err error) {
|
||||||
return DebugSql(l)
|
return debugSql(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) {
|
func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) {
|
||||||
|
|
@ -94,17 +94,17 @@ func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) Query(db execution.DB, destination interface{}) error {
|
func (l *lockStatementImpl) Query(db execution.DB, destination interface{}) error {
|
||||||
return Query(l, db, destination)
|
return query(l, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (l *lockStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return QueryContext(l, db, context, destination)
|
return queryContext(l, db, context, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) Exec(db execution.DB) (sql.Result, error) {
|
func (l *lockStatementImpl) Exec(db execution.DB) (sql.Result, error) {
|
||||||
return Exec(l, db)
|
return exec(l, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
func (l *lockStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
return ExecContext(l, db, context)
|
return execContext(l, db, context)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ func (s *selectStatementImpl) Sql() (query string, args []interface{}, err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) DebugSql() (query string, err error) {
|
func (s *selectStatementImpl) DebugSql() (query string, err error) {
|
||||||
return DebugSql(s)
|
return debugSql(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) projections() []projection {
|
func (s *selectStatementImpl) projections() []projection {
|
||||||
|
|
@ -290,17 +290,17 @@ func (s *selectLockImpl) serialize(statement statementType, out *queryData, opti
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) Query(db execution.DB, destination interface{}) error {
|
func (s *selectStatementImpl) Query(db execution.DB, destination interface{}) error {
|
||||||
return Query(s, db, destination)
|
return query(s, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (s *selectStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return QueryContext(s, db, context, destination)
|
return queryContext(s, db, context, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (s *selectStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
return Exec(s, db)
|
return exec(s, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
func (s *selectStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
return ExecContext(s, db, context)
|
return execContext(s, db, context)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -200,21 +200,21 @@ func (s *setStatementImpl) Sql() (query string, args []interface{}, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setStatementImpl) DebugSql() (query string, err error) {
|
func (s *setStatementImpl) DebugSql() (query string, err error) {
|
||||||
return DebugSql(s)
|
return debugSql(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setStatementImpl) Query(db execution.DB, destination interface{}) error {
|
func (s *setStatementImpl) Query(db execution.DB, destination interface{}) error {
|
||||||
return Query(s, db, destination)
|
return query(s, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (s *setStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return QueryContext(s, db, context, destination)
|
return queryContext(s, db, context, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (s *setStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
return Exec(s, db)
|
return exec(s, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
func (s *setStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
return ExecContext(s, db, context)
|
return execContext(s, db, context)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
statement.go
23
statement.go
|
|
@ -9,19 +9,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Statement interface {
|
type Statement interface {
|
||||||
// String returns generated SQL as string.
|
// Sql returns parametrized sql query with list of arguments.
|
||||||
|
// err is returned if statement is not composed correctly
|
||||||
Sql() (query string, args []interface{}, err error)
|
Sql() (query string, args []interface{}, err error)
|
||||||
|
// 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.
|
||||||
|
// err is returned if statement is not composed correctly
|
||||||
DebugSql() (query string, err error)
|
DebugSql() (query string, err error)
|
||||||
|
|
||||||
|
// Query executes statement over database connection db and stores row result in destination.
|
||||||
|
// Destination can be arbitrary structure
|
||||||
Query(db execution.DB, destination interface{}) error
|
Query(db execution.DB, destination interface{}) error
|
||||||
|
// QueryContext executes statement with a context over database connection db and stores row result in destination.
|
||||||
|
// Destination can be of arbitrary structure
|
||||||
QueryContext(db execution.DB, context context.Context, destination interface{}) error
|
QueryContext(db execution.DB, context context.Context, destination interface{}) error
|
||||||
|
|
||||||
|
//Exec executes statement over db connection without returning any rows.
|
||||||
Exec(db execution.DB) (sql.Result, error)
|
Exec(db execution.DB) (sql.Result, error)
|
||||||
|
//Exec executes statement with context over db connection without returning any rows.
|
||||||
ExecContext(db execution.DB, context context.Context) (sql.Result, error)
|
ExecContext(db execution.DB, context context.Context) (sql.Result, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DebugSql(statement Statement) (string, error) {
|
func debugSql(statement Statement) (string, error) {
|
||||||
sqlQuery, args, err := statement.Sql()
|
sqlQuery, args, err := statement.Sql()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -38,7 +47,7 @@ func DebugSql(statement Statement) (string, error) {
|
||||||
return debugSqlQuery, nil
|
return debugSqlQuery, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Query(statement Statement, db execution.DB, destination interface{}) error {
|
func query(statement Statement, db execution.DB, destination interface{}) error {
|
||||||
query, args, err := statement.Sql()
|
query, args, err := statement.Sql()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -48,7 +57,7 @@ func Query(statement Statement, db execution.DB, destination interface{}) error
|
||||||
return execution.Query(db, context.Background(), query, args, destination)
|
return execution.Query(db, context.Background(), query, args, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func QueryContext(statement Statement, db execution.DB, context context.Context, destination interface{}) error {
|
func queryContext(statement Statement, db execution.DB, context context.Context, destination interface{}) error {
|
||||||
query, args, err := statement.Sql()
|
query, args, err := statement.Sql()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -58,7 +67,7 @@ func QueryContext(statement Statement, db execution.DB, context context.Context,
|
||||||
return execution.Query(db, context, query, args, destination)
|
return execution.Query(db, context, query, args, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Exec(statement Statement, db execution.DB) (res sql.Result, err error) {
|
func exec(statement Statement, db execution.DB) (res sql.Result, err error) {
|
||||||
query, args, err := statement.Sql()
|
query, args, err := statement.Sql()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -68,7 +77,7 @@ func Exec(statement Statement, db execution.DB) (res sql.Result, err error) {
|
||||||
return db.Exec(query, args...)
|
return db.Exec(query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecContext(statement Statement, db execution.DB, context context.Context) (res sql.Result, err error) {
|
func execContext(statement Statement, db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
query, args, err := statement.Sql()
|
query, args, err := statement.Sql()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,12 @@ ORDER BY payment.payment_id ASC
|
||||||
LIMIT 30;
|
LIMIT 30;
|
||||||
`
|
`
|
||||||
|
|
||||||
query := SELECT(Payment.AllColumns, Customer.AllColumns).
|
query := SELECT(
|
||||||
FROM(Payment.INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))).
|
Payment.AllColumns,
|
||||||
|
Customer.AllColumns,
|
||||||
|
).
|
||||||
|
FROM(Payment.
|
||||||
|
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))).
|
||||||
ORDER_BY(Payment.PaymentID.ASC()).
|
ORDER_BY(Payment.PaymentID.ASC()).
|
||||||
LIMIT(30)
|
LIMIT(30)
|
||||||
|
|
||||||
|
|
@ -599,7 +603,9 @@ SELECT actor.actor_id AS "actor.actor_id",
|
||||||
film_actor.actor_id AS "film_actor.actor_id",
|
film_actor.actor_id AS "film_actor.actor_id",
|
||||||
film_actor.film_id AS "film_actor.film_id",
|
film_actor.film_id AS "film_actor.film_id",
|
||||||
film_actor.last_update AS "film_actor.last_update",
|
film_actor.last_update AS "film_actor.last_update",
|
||||||
"rFilms"."film.title" AS "film.title"
|
"rFilms"."film.film_id" AS "film.film_id",
|
||||||
|
"rFilms"."film.title" AS "film.title",
|
||||||
|
"rFilms"."film.rating" AS "film.rating"
|
||||||
FROM dvds.actor
|
FROM dvds.actor
|
||||||
INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.film_id)
|
INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.film_id)
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
|
|
@ -621,7 +627,6 @@ FROM dvds.actor
|
||||||
AsTable("rFilms")
|
AsTable("rFilms")
|
||||||
|
|
||||||
rFilmId := Film.FilmID.From(rRatingFilms)
|
rFilmId := Film.FilmID.From(rRatingFilms)
|
||||||
rTitle := Film.Title.From(rRatingFilms)
|
|
||||||
|
|
||||||
query := Actor.
|
query := Actor.
|
||||||
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.FilmID)).
|
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.FilmID)).
|
||||||
|
|
@ -629,10 +634,10 @@ FROM dvds.actor
|
||||||
SELECT(
|
SELECT(
|
||||||
Actor.AllColumns,
|
Actor.AllColumns,
|
||||||
FilmActor.AllColumns,
|
FilmActor.AllColumns,
|
||||||
rTitle.AS("film.title"),
|
rRatingFilms.AllColumns(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fmt.Println(query.Sql())
|
fmt.Println(query.DebugSql())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedQuery)
|
assertStatementSql(t, query, expectedQuery)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,21 +136,21 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) DebugSql() (query string, err error) {
|
func (u *updateStatementImpl) DebugSql() (query string, err error) {
|
||||||
return DebugSql(u)
|
return debugSql(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) Query(db execution.DB, destination interface{}) error {
|
func (u *updateStatementImpl) Query(db execution.DB, destination interface{}) error {
|
||||||
return Query(u, db, destination)
|
return query(u, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (u *updateStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return QueryContext(u, db, context, destination)
|
return queryContext(u, db, context, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (u *updateStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
return Exec(u, db)
|
return exec(u, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
func (u *updateStatementImpl) ExecContext(db execution.DB, context context.Context) (res sql.Result, err error) {
|
||||||
return ExecContext(u, db, context)
|
return execContext(u, db, context)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ Following operators are only available on string expressions:
|
||||||
| NOT_SIMILAR_TO | table.Film.Name.NOT_SIMILAR_TO(String("%Wind%")) | staff.active NOT SIMILAR TO %Wind% |
|
| NOT_SIMILAR_TO | table.Film.Name.NOT_SIMILAR_TO(String("%Wind%")) | staff.active NOT SIMILAR TO %Wind% |
|
||||||
|
|
||||||
|
|
||||||
## Cast operators
|
## SQL Cast operators
|
||||||
|
|
||||||
Cast operators allow expressions to be casted to some other database type.
|
Cast operators allow expressions to be casted to some other database type.
|
||||||
SQL builder expression type changes accordingly to database type.
|
SQL builder expression type changes accordingly to database type.
|
||||||
|
|
@ -158,4 +158,6 @@ SQL builder expression type changes accordingly to database type.
|
||||||
| TO_TIMESTAMP | table.Film.Description.TO_TIMESTAMP() | film.description::timestamp |
|
| TO_TIMESTAMP | table.Film.Description.TO_TIMESTAMP() | film.description::timestamp |
|
||||||
| TO_TIMESTAMPZ | table.Film.Description.TO_TIMESTAMPZ() | film.description::timestampz |
|
| TO_TIMESTAMPZ | table.Film.Description.TO_TIMESTAMPZ() | film.description::timestampz |
|
||||||
|
|
||||||
|
## SQL builder cast
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
|
||||||
248
wiki/SELECT.md
248
wiki/SELECT.md
|
|
@ -0,0 +1,248 @@
|
||||||
|
|
||||||
|
SELECT statement is used to retrieve records from one or more tables in PostgreSQL.
|
||||||
|
More about SELECT statement in postgres can be found at: https://www.postgresql.org/docs/11/sql-select.html
|
||||||
|
|
||||||
|
|
||||||
|
## SELECT statement clauses
|
||||||
|
|
||||||
|
Following clauses are supported - SELECT, DISTINCT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET and FOR.
|
||||||
|
_This list might be extended with feature Jet releases._
|
||||||
|
|
||||||
|
##### 1. SELECT clause
|
||||||
|
|
||||||
|
Sample SELECT clause written in Go:
|
||||||
|
```
|
||||||
|
jet.SELECT(
|
||||||
|
jet.Int(1).ADD(jet.Int(12)).SUB(jet.Int(21)), // arbitrary expression
|
||||||
|
table.Film.Name, // column
|
||||||
|
table.Customer.FirstName.CONCAT(table.Customer.LastName).AS("FullName") // alias
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
If jet and autogenerated table package, is dot "." imported, above statement will look more like native SQL:
|
||||||
|
|
||||||
|
```
|
||||||
|
SELECT(
|
||||||
|
Int(1).ADD(Int(12)).SUB(Int(21)), // arbitrary expression
|
||||||
|
Film.Name, // column
|
||||||
|
Customer.FirstName.CONCAT(Customer.LastName).AS("FullName") // alias
|
||||||
|
)
|
||||||
|
```
|
||||||
|
*For the most of the wiki dot import is used.*
|
||||||
|
|
||||||
|
Above SQL clause written in go will produce following raw SQL:
|
||||||
|
|
||||||
|
```
|
||||||
|
SELECT 1 + 12 - 21,
|
||||||
|
film.name AS "film.name", --
|
||||||
|
customer.first_name || customer.last_name AS "FullName"
|
||||||
|
```
|
||||||
|
`film.name AS "film.name"` - column names are aliased by default. Alias is used during execution to map row result to
|
||||||
|
appropriate `model` structure.
|
||||||
|
|
||||||
|
##### 2. DISTINCT clause
|
||||||
|
|
||||||
|
```
|
||||||
|
SELECT(Film.Name).
|
||||||
|
.DISTINCT().
|
||||||
|
```
|
||||||
|
|
||||||
|
Raw SQL:
|
||||||
|
|
||||||
|
```
|
||||||
|
SELECT DISTINCT film.name
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 3. FROM clause
|
||||||
|
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
1).FROM(Film)
|
||||||
|
2).FROM(
|
||||||
|
Film.
|
||||||
|
INNER_JOIN(Language, Langauge.LanguageID.EQ(Film.FilmID))
|
||||||
|
)
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
1)FROM dvds.film
|
||||||
|
2)FROM Film
|
||||||
|
INNER JOIN Language ON (Language.LanguageID = Film.FilmID)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 4. WHERE clause
|
||||||
|
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.WHERE(Film.Length.GT(Int(150)))
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
WHERE film.length > 150
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 5. GROUP BY clause
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.GROUP_BY(Film.Length)
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
GROUP BY film.length
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 6. HAVING clause
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.HAVING(Film.Length.GT(Int(150))
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
HAVING film.length > 150
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 7. ORDER BY clause
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.ORDER_BY(Film.Length)
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
ORDER BY film.length
|
||||||
|
```
|
||||||
|
##### 8. LIMIT clause
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.LIMIT(11)
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
LIMIT 11
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 9. OFFSET clause
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.OFFSET(11)
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
OFFSET 11
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 9. FOR clause
|
||||||
|
```
|
||||||
|
Go:
|
||||||
|
.FOR(jet.NO_KEY_UPDATE)
|
||||||
|
|
||||||
|
SQL:
|
||||||
|
FOR NO KEY UPDATE
|
||||||
|
```
|
||||||
|
|
||||||
|
### Two forms of select statements in Jet
|
||||||
|
|
||||||
|
#### 1. Classical select statement
|
||||||
|
Columns selected are before tables selected
|
||||||
|
```
|
||||||
|
SELECT(
|
||||||
|
Payment.AllColumns,
|
||||||
|
Customer.AllColumns,
|
||||||
|
).
|
||||||
|
FROM(Payment.
|
||||||
|
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))).
|
||||||
|
ORDER_BY(Payment.PaymentID.ASC()).
|
||||||
|
LIMIT(30)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Jet select statement
|
||||||
|
Joined tables(or just one) are before columns selected. There is no FROM.
|
||||||
|
```
|
||||||
|
Payment.
|
||||||
|
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))
|
||||||
|
SELECT(
|
||||||
|
Payment.AllColumns,
|
||||||
|
Customer.AllColumns,
|
||||||
|
).
|
||||||
|
ORDER_BY(Payment.PaymentID.ASC()).
|
||||||
|
LIMIT(30)
|
||||||
|
```
|
||||||
|
|
||||||
|
Second form is added, because sometimes feels more natural to first think about the tables
|
||||||
|
of interest, and than about the columns.
|
||||||
|
**Both forms produces exactly the same raw SQL.**
|
||||||
|
|
||||||
|
## Sub-queries
|
||||||
|
|
||||||
|
How to write SELECT statement with sub-queries?
|
||||||
|
|
||||||
|
Sub-queries are composed first:
|
||||||
|
```
|
||||||
|
// select film_id and title from film table that have 'R' rating.
|
||||||
|
rRatingFilms := Film.
|
||||||
|
SELECT(
|
||||||
|
Film.FilmID,
|
||||||
|
Film.Title,
|
||||||
|
).
|
||||||
|
WHERE(Film.Rating.EQ(enum.MpaaRating.R)).
|
||||||
|
AsTable("rFilms")
|
||||||
|
```
|
||||||
|
`AsTable("rFilms")` - allows SELECT statements to be seen as table.
|
||||||
|
|
||||||
|
To use sub-query columns in SELECT statement expressions we have to export column from sub-query,
|
||||||
|
using `From` method.
|
||||||
|
|
||||||
|
```
|
||||||
|
rFilmId := Film.FilmID.From(rRatingFilms) //used for join condition
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can write:
|
||||||
|
|
||||||
|
```
|
||||||
|
query := Actor.
|
||||||
|
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.FilmID)).
|
||||||
|
INNER_JOIN(rRatingFilms, FilmActor.FilmID.EQ(rFilmId)).
|
||||||
|
SELECT(
|
||||||
|
Actor.AllColumns,
|
||||||
|
FilmActor.AllColumns,
|
||||||
|
rRatingFilms.AllColumns(),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
`rRatingFilms.AllColumns(),` - sub-query columns needed for projection can be exported with AllColumns() method.
|
||||||
|
No need to export each one of them with `From`.
|
||||||
|
|
||||||
|
Debug SQL of above example:
|
||||||
|
```sql
|
||||||
|
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",
|
||||||
|
film_actor.actor_id AS "film_actor.actor_id",
|
||||||
|
film_actor.film_id AS "film_actor.film_id",
|
||||||
|
film_actor.last_update AS "film_actor.last_update",
|
||||||
|
"rFilms"."film.film_id" AS "film.film_id",
|
||||||
|
"rFilms"."film.title" AS "film.title",
|
||||||
|
"rFilms"."film.rating" AS "film.rating"
|
||||||
|
FROM dvds.actor
|
||||||
|
INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.film_id)
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT film.film_id AS "film.film_id",
|
||||||
|
film.title AS "film.title",
|
||||||
|
film.rating AS "film.rating"
|
||||||
|
FROM dvds.film
|
||||||
|
WHERE film.rating = 'R'
|
||||||
|
) AS "rFilms" ON (film_actor.film_id = "rFilms"."film.film_id");
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### What If sub-query projection is not a column?
|
||||||
|
For instance:
|
||||||
|
```
|
||||||
|
customersPayments := Payment.
|
||||||
|
SELECT(
|
||||||
|
Payment.CustomerID,
|
||||||
|
SUMf(Payment.Amount).AS("amount_sum"),
|
||||||
|
).
|
||||||
|
GROUP_BY(Payment.CustomerID).
|
||||||
|
AsTable("customer_payment_sum")
|
||||||
|
|
||||||
|
customerId := Payment.CustomerID.From(customersPayments)
|
||||||
|
```
|
||||||
|
|
||||||
|
To export `"amount_sum"` from `customersPayments` sub-query we have to create column first with appropriate type and a name.
|
||||||
|
Because SUMf produces float expression we will create FloatColumn with name of the column alias `"amount_sum"`
|
||||||
|
```
|
||||||
|
amountSum := FloatColumn("amount_sum").From(customersPayments)
|
||||||
|
```
|
||||||
35
wiki/Statements.md
Normal file
35
wiki/Statements.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
Following statements are supported:
|
||||||
|
|
||||||
|
* [SELECT](https://github.com/go-jet/jet/wiki/SELECT)
|
||||||
|
* [INSERT](https://github.com/go-jet/jet/wiki/INSERT)
|
||||||
|
* [UPDATE](https://github.com/go-jet/jet/wiki/UPDATE)
|
||||||
|
* [DELETE](https://github.com/go-jet/jet/wiki/DELETE)
|
||||||
|
* [LOCK](https://github.com/go-jet/jet/wiki/LOCK)
|
||||||
|
|
||||||
|
_This list might be extended with feature Jet releases._
|
||||||
|
|
||||||
|
There is a common set of action that can be performed for each statement type:
|
||||||
|
|
||||||
|
- `Sql() (query string, args []interface{}, err error)` - retrieves parametrized sql query with list of arguments
|
||||||
|
- `DebugSql() (query string, err error)` - retrieves debug query where every parametrized placeholder is replaced with its argument.
|
||||||
|
- `Query(db execution.DB, destination interface{}) error` - executes statements over database connection db and stores row result in destination.
|
||||||
|
- `QueryContext(db execution.DB, context context.Context, destination interface{}) error` - executes statement with a context over database connection db and stores row result in destination.
|
||||||
|
- `Exec(db execution.DB) (sql.Result, error)` - executes statement over db connection without returning any rows.
|
||||||
|
- `ExecContext(db execution.DB, context context.Context) (sql.Result, error)` - executes statement with context over db connection without returning any rows.
|
||||||
|
|
||||||
|
Database connection can be of any type that implements following interface:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type DB interface {
|
||||||
|
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||||
|
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||||
|
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These include but are not limited to:
|
||||||
|
- `sql.DB`
|
||||||
|
- `sql.Tx`
|
||||||
|
- `sql.Conn`
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
* [Generator](https://github.com/go-jet/jet/wiki/Generator)
|
* [Generator](https://github.com/go-jet/jet/wiki/Generator)
|
||||||
* [Writing SQL in Go]()
|
* [Writing SQL in Go]()
|
||||||
* [Expressions](https://github.com/go-jet/jet/wiki/Expressions)
|
* [Expressions](https://github.com/go-jet/jet/wiki/Expressions)
|
||||||
* [Statements]()
|
* [Statements](https://github.com/go-jet/jet/wiki/Statements)
|
||||||
* [SELECT]()
|
* [SELECT](https://github.com/go-jet/jet/wiki/SELECT)
|
||||||
* [INSERT]()
|
* [INSERT](https://github.com/go-jet/jet/wiki/INSERT)
|
||||||
* [UPDATE]()
|
* [UPDATE](https://github.com/go-jet/jet/wiki/UPDATE)
|
||||||
* [DELETE]()
|
* [DELETE](https://github.com/go-jet/jet/wiki/DELETE)
|
||||||
* [LOCK]()
|
* [LOCK](https://github.com/go-jet/jet/wiki/LOCK)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue