gosqle
gosqle is a golang package that can generate sql queries.
Table of Contents:
Examples
Examples shown here are generated into this README.md file from the examples folder. See README.tmpl.md for more information.
To generate the examples into this README.md file, run the following command:
./run_readme.sh
To run examples from the examples folder, run the following command:
docker-compose up -d
# if needed you can seed the database with some data
./run_seed.sh
./run_examples.sh
Select
Create a select statement with the following syntax:
gosqle.NewSelect(...columns)
Generate a select query:
SELECT id, name, email FROM users LIMIT 10;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
)
// SelectUsers selects users.
func SelectUsers(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
clauses.Selectable{Expr: expressions.Column{Name: "name"}},
clauses.Selectable{Expr: expressions.Column{Name: "email"}},
).
FromTable("addresses", nil).
Limit(args.NewArgument(10)).
Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
err = rows.Scan(&user.ID, &user.Name, &user.Email)
if err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Generate select query using group by and aggregate functions:
SELECT country, COUNT(id) AS address_count
FROM addresses
GROUP BY country
ORDER BY address_count DESC;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/clauses/groupby"
"github.com/dwethmar/gosqle/clauses/orderby"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
)
type AmountOfAddressesPerCountry struct {
Country string
Count int64
}
// SelectAmountOfAddressesPerCountry select amount of addresses per country
func SelectAmountOfAddressesPerCountry(db *sql.DB) ([]AmountOfAddressesPerCountry, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{
Expr: &expressions.Column{Name: "country"},
},
clauses.Selectable{
Expr: expressions.NewCount(&expressions.Column{Name: "id"}),
As: "address_count",
},
).FromTable("addresses", nil).GroupBy(groupby.ColumnGrouping{
&expressions.Column{Name: "country"},
}).OrderBy(orderby.Sort{
Column: &expressions.Column{Name: "address_count"},
Direction: orderby.DESC,
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var r []AmountOfAddressesPerCountry
for rows.Next() {
var a AmountOfAddressesPerCountry
err = rows.Scan(&a.Country, &a.Count)
if err != nil {
return nil, "", err
}
r = append(r, a)
}
return r, sb.String(), nil
}
Subquery
SELECT name
FROM users
WHERE id IN (
SELECT user_id
FROM addresses
WHERE city = 'Amsterdam'
);
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/clauses/from"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// SelectUsers selects users.
func PeopleOfAmsterdam(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "name"}},
).From(
from.NewFrom("users", ""),
).Where(
predicates.In{
Col: expressions.Column{Name: "id"},
Expr: gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "user_id"}},
).From(
from.NewFrom("addresses", ""),
).Where(predicates.EQ{
Col: expressions.Column{Name: "city"},
Expr: args.NewArgument("Amsterdam"),
}).Statement, // <- This is the subquery, so without semicolon.
},
).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
err = rows.Scan(&user.Name)
if err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Insert
gosqle.NewInsert(table, ...columns)
Generate an insert query:
INSERT INTO users (name, email) VALUES ($1, $2)
package main
import (
"database/sql"
"fmt"
"strings"
"time"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/postgres"
)
// InsertUser inserts a user.
func InsertUser(db *sql.DB) (string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewInsert("users", "name", "email").Values(
args.NewArgument("John"),
args.NewArgument(fmt.Sprintf("john%d@%s", time.Now().Unix(), "example.com")),
).Write(sb)
if err != nil {
return "", err
}
if _, err = db.Exec(sb.String(), args.Args...); err != nil {
return "", err
}
return sb.String(), nil
}
Delete
Generate a delete query:
DELETE FROM users WHERE id = $1
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// Delete deletes a user.
func DeleteAddress(db *sql.DB) (string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
// DELETE FROM addresses WHERE user_id = $1
err := gosqle.NewDelete("addresses").Where(predicates.EQ{
Col: expressions.Column{Name: "user_id"},
Expr: args.NewArgument(111),
}).Write(sb)
if err != nil {
return "", err
}
if _, err = db.Exec(sb.String(), args.Args...); err != nil {
return "", err
}
return sb.String(), nil
}
Update
Generate an update query:
UPDATE users SET name = $1 WHERE id = $2
package main
import (
"database/sql"
"fmt"
"strings"
"time"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses/set"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// UpdateUser updates a user.
func UpdateUser(db *sql.DB) (string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewUpdate("users").Set(set.Change{
Col: "name",
Expr: args.NewArgument(fmt.Sprintf("new name %d", time.Now().Unix())),
}).Where(predicates.EQ{
Col: expressions.Column{Name: "id"},
Expr: args.NewArgument(1),
}).Write(sb)
if err != nil {
return "", err
}
if _, err = db.Exec(sb.String(), args.Args...); err != nil {
return "", err
}
return sb.String(), nil
}
Where conditions
equal
SELECT id FROM users WHERE name = $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereEQ selects users where name is equal to 'John'.
func WhereEQ(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.EQ{
Col: expressions.Column{Name: "name"},
Expr: args.NewArgument("John"),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Not equal
SELECT id FROM users WHERE name != $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereNE selects users where name is not equal to 'John'.
func WhereNE(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.NE{
Col: expressions.Column{Name: "name"},
Expr: args.NewArgument("John"),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Greater than
SELECT id FROM users WHERE id > $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereGT selects users where id is greater than 10
func WhereGT(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.GT{
Col: expressions.Column{Name: "id"},
Expr: args.NewArgument(10),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Greater than or equal
SELECT id FROM users WHERE id >= $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereGTE selects users where id is greater than or equal to 10
func WhereGTE(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.GTE{
Col: expressions.Column{Name: "id"},
Expr: args.NewArgument(10),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Less than
SELECT id FROM users WHERE id < $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereLT selects users where id is less than 10
func WhereLT(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.LT{
Col: expressions.Column{Name: "id"},
Expr: args.NewArgument(10),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Less than or equal
SELECT id FROM users WHERE id <= $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereLTE selects users where id is less than or equal to 10
func WhereLTE(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.LT{
Col: expressions.Column{Name: "id"},
Expr: args.NewArgument(10),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Like
SELECT id FROM users WHERE name LIKE $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereLike selects users where name is like anna%
func WhereLike(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.Like{
Col: expressions.Column{Name: "name"},
Expr: args.NewArgument("anna%"),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
In
SELECT id FROM users WHERE name IN ($1, $2, $3);
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereIN selects users where name is in 'John', 'Jane' or 'Joe'.
func WhereIN(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.In{
Col: expressions.Column{Name: "id"},
Expr: expressions.List{
args.NewArgument("John"),
args.NewArgument("Jane"),
args.NewArgument("Joe"),
},
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Between
SELECT id FROM users WHERE id BETWEEN $1 AND $2;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereBetween selects users where id is between 10 and 20
func WhereBetween(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).
Where(predicates.Between{
Col: expressions.Column{Name: "id"},
Low: args.NewArgument(10),
High: args.NewArgument(20),
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Is null
SELECT id FROM addresses WHERE phone IS NULL;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereIsNull selects addresses where phone is null
func WhereIsNull(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.IsNull{
Col: expressions.Column{Name: "phone"},
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Grouping
SELECT id FROM users WHERE (id BETWEEN $1 AND $2 OR id BETWEEN $3 AND $4) OR name = $5;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereWrap selects users where id is between 10 and 20 or 30 and 40 or name is john
func WhereWrap(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(
predicates.Wrap{
Predicates: []predicates.Predicate{
predicates.Between{
Col: expressions.Column{Name: "id"},
Low: args.NewArgument(10),
High: args.NewArgument(20),
},
predicates.Between{
Col: expressions.Column{Name: "id"},
Low: args.NewArgument(30),
High: args.NewArgument(40),
},
},
}, predicates.EQ{
Col: expressions.Column{Name: "name"},
Expr: args.NewArgument("John"),
Logic: predicates.OR,
},
).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Not
SELECT id FROM users WHERE NOT name = $1;
package main
import (
"database/sql"
"strings"
"github.com/dwethmar/gosqle"
"github.com/dwethmar/gosqle/clauses"
"github.com/dwethmar/gosqle/expressions"
"github.com/dwethmar/gosqle/postgres"
"github.com/dwethmar/gosqle/predicates"
)
// WhereNOT selects users where name is not John.
func WhereNOT(db *sql.DB) ([]User, string, error) {
sb := new(strings.Builder)
args := postgres.NewArguments()
err := gosqle.NewSelect(
clauses.Selectable{Expr: expressions.Column{Name: "id"}},
).FromTable("users", nil).Where(predicates.Not{
Predicate: predicates.EQ{
Col: expressions.Column{Name: "name"},
Expr: args.NewArgument("John"),
},
}).Write(sb)
if err != nil {
return nil, "", err
}
rows, err := db.Query(sb.String(), args.Args...)
if err != nil {
return nil, "", err
}
var users []User
for rows.Next() {
var user User
if err = rows.Scan(&user.ID); err != nil {
return nil, "", err
}
users = append(users, user)
}
return users, sb.String(), nil
}
Syntax used
