Skip to content

Commit

Permalink
Merge pull request #87 from ulule/dev
Browse files Browse the repository at this point in the history
Loukoum v3.3.0
  • Loading branch information
novln authored Dec 15, 2019
2 parents a9f7064 + ba08639 commit d2f4f2d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 55 deletions.
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Documentation][godoc-img]][godoc-url]
![License][license-img]

*A simple SQL Query Builder.*
_A simple SQL Query Builder._

[![Loukoum][loukoum-img]][loukoum-url]

Expand All @@ -18,26 +18,26 @@ Afraid to slip a tiny **SQL injection** manipulating `fmt` to append conditions?

Just a few examples when and where loukoum can become handy:

* Remove user anonymity if user is an admin
* Display news draft for an author
* Add filters in query based on request parameters
* Add a `ON CONFLICT` clause for resource's owner
* And so on...
- Remove user anonymity if user is an admin
- Display news draft for an author
- Add filters in query based on request parameters
- Add a `ON CONFLICT` clause for resource's owner
- And so on...

## Installation

Using [Go Modules](https://github.com/golang/go/wiki/Modules)

```console
go get github.com/ulule/loukoum/v3@v3.2.1
go get github.com/ulule/loukoum/v3@v3.3.0
```

## Usage

Loukoum helps you generate SQL queries from composable parts.

However, keep in mind it's not an ORM or a Mapper so you have to use a SQL connector ([database/sql][sql-url], [sqlx][sqlx-url], etc.)
to execute queries.
However, keep in mind it's not an ORM or a Mapper so you have to use a SQL connector
([database/sql][sql-url], [sqlx][sqlx-url], [makroud][makroud-url], etc.) to execute queries.

### INSERT

Expand Down Expand Up @@ -385,22 +385,22 @@ See [examples](examples/named) directory for more information.

### Migrating from v2.x.x

* Migrate from [dep](https://github.com/golang/dep) to [go modules](https://github.com/golang/go/wiki/Modules) by
replacing the import path `github.com/ulule/loukoum/...` by `github.com/ulule/loukoum/v3/...`
- Migrate from [dep](https://github.com/golang/dep) to [go modules](https://github.com/golang/go/wiki/Modules) by
replacing the import path `github.com/ulule/loukoum/...` by `github.com/ulule/loukoum/v3/...`

### Migrating from v1.x.x

* Change `Prepare()` to `NamedQuery()` for [builder.Builder](https://github.com/ulule/loukoum/blob/d6ee7eac818ec74889870fa82dff411ea266463b/builder/builder.go#L19) interface.
- Change `Prepare()` to `NamedQuery()` for [builder.Builder](https://github.com/ulule/loukoum/blob/d6ee7eac818ec74889870fa82dff411ea266463b/builder/builder.go#L19) interface.

## Inspiration

* [squirrel](https://github.com/Masterminds/squirrel)
* [goqu](https://github.com/doug-martin/goqu)
* [sqlabble](https://github.com/minodisk/sqlabble)
- [squirrel](https://github.com/Masterminds/squirrel)
- [goqu](https://github.com/doug-martin/goqu)
- [sqlabble](https://github.com/minodisk/sqlabble)

## Thanks

* [Ilia Choly](https://github.com/icholy)
- [Ilia Choly](https://github.com/icholy)

## License

Expand All @@ -410,12 +410,12 @@ Loukoum artworks are released under the [`Creative Commons BY-SA License`][artwo

## Contributing

* Ping us on twitter:
* [@novln_](https://twitter.com/novln_)
* [@oibafsellig](https://twitter.com/oibafsellig)
* [@thoas](https://twitter.com/thoas)
* Fork the [project](https://github.com/ulule/loukoum)
* Fix [bugs](https://github.com/ulule/loukoum/issues)
- Ping us on twitter:
- [@novln\_](https://twitter.com/novln_)
- [@oibafsellig](https://twitter.com/oibafsellig)
- [@thoas](https://twitter.com/thoas)
- Fork the [project](https://github.com/ulule/loukoum)
- Fix [bugs](https://github.com/ulule/loukoum/issues)

**Don't hesitate ;)**

Expand All @@ -428,5 +428,6 @@ Loukoum artworks are released under the [`Creative Commons BY-SA License`][artwo
[artwork-license-url]: docs/images/LICENSE
[sql-url]: https://golang.org/pkg/database/sql/
[sqlx-url]: https://github.com/jmoiron/sqlx
[makroud-url]: https://github.com/ulule/makroud/
[circle-url]: https://circleci.com/gh/ulule/loukoum/tree/master
[circle-img]: https://circleci.com/gh/ulule/loukoum.svg?style=shield&circle-token=1de7bc4fd603b0df406ceef4bbba3fb3d6b5ed10
34 changes: 34 additions & 0 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,37 @@ func ToSet(args []interface{}) stmt.Set {
set = MergeSet(set, args)
return set
}

// ToLimit takes an empty interfaces and returns a Limit instance.
func ToLimit(arg interface{}) stmt.Limit {
switch value := arg.(type) {
case stmt.Limit:
return value
default:
limit, ok := ToInt64(value)
if !ok {
panic(fmt.Sprintf("loukoum: cannot use %T as limit", value))
}
if limit <= 0 {
panic("loukoum: limit must be a positive integer")
}
return stmt.NewLimit(limit)
}
}

// ToOffset takes an empty interfaces and returns a Offset instance.
func ToOffset(arg interface{}) stmt.Offset {
switch value := arg.(type) {
case stmt.Offset:
return value
default:
offset, ok := ToInt64(value)
if !ok {
panic(fmt.Sprintf("loukoum: cannot use %T as offset", value))
}
if offset < 0 {
panic("loukoum: offset must be a non-negative integer")
}
return stmt.NewOffset(offset)
}
}
24 changes: 12 additions & 12 deletions builder/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,10 @@ func TestInsert_Returning(t *testing.T) {
Insert("table").
Columns("a", "b", "c").
Values([]string{"va", "vb", "vc"}).
Returning("a", "b"),
String: "INSERT INTO table (a, b, c) VALUES ('va', 'vb', 'vc') RETURNING a, b",
Query: "INSERT INTO table (a, b, c) VALUES ($1, $2, $3) RETURNING a, b",
NamedQuery: "INSERT INTO table (a, b, c) VALUES (:arg_1, :arg_2, :arg_3) RETURNING a, b",
Returning("b", "a"),
String: "INSERT INTO table (a, b, c) VALUES ('va', 'vb', 'vc') RETURNING b, a",
Query: "INSERT INTO table (a, b, c) VALUES ($1, $2, $3) RETURNING b, a",
NamedQuery: "INSERT INTO table (a, b, c) VALUES (:arg_1, :arg_2, :arg_3) RETURNING b, a",
Args: []interface{}{"va", "vb", "vc"},
},
{
Expand All @@ -364,10 +364,10 @@ func TestInsert_Returning(t *testing.T) {
Insert("table").
Columns("a", "b", "c").
Values([]string{"va", "vb", "vc"}).
Returning("a", "b", "c"),
String: "INSERT INTO table (a, b, c) VALUES ('va', 'vb', 'vc') RETURNING a, b, c",
Query: "INSERT INTO table (a, b, c) VALUES ($1, $2, $3) RETURNING a, b, c",
NamedQuery: "INSERT INTO table (a, b, c) VALUES (:arg_1, :arg_2, :arg_3) RETURNING a, b, c",
Returning("b", "a", "c"),
String: "INSERT INTO table (a, b, c) VALUES ('va', 'vb', 'vc') RETURNING b, a, c",
Query: "INSERT INTO table (a, b, c) VALUES ($1, $2, $3) RETURNING b, a, c",
NamedQuery: "INSERT INTO table (a, b, c) VALUES (:arg_1, :arg_2, :arg_3) RETURNING b, a, c",
Args: []interface{}{"va", "vb", "vc"},
},
{
Expand All @@ -388,18 +388,18 @@ func TestInsert_Returning(t *testing.T) {
Insert("table").
Columns("a", "b", "c").
Values([]string{"va", "vb", "vc"}).
Returning(loukoum.Column("a").As("alias_a"), loukoum.Column("b").As("alias_b")),
Returning(loukoum.Column("b").As("alias_b"), loukoum.Column("a").As("alias_a")),
String: fmt.Sprint(
"INSERT INTO table (a, b, c) VALUES ('va', 'vb', 'vc') ",
"RETURNING a AS alias_a, b AS alias_b",
"RETURNING b AS alias_b, a AS alias_a",
),
Query: fmt.Sprint(
"INSERT INTO table (a, b, c) VALUES ($1, $2, $3) ",
"RETURNING a AS alias_a, b AS alias_b",
"RETURNING b AS alias_b, a AS alias_a",
),
NamedQuery: fmt.Sprint(
"INSERT INTO table (a, b, c) VALUES (:arg_1, :arg_2, :arg_3) ",
"RETURNING a AS alias_a, b AS alias_b",
"RETURNING b AS alias_b, a AS alias_a",
),
Args: []interface{}{"va", "vb", "vc"},
},
Expand Down
16 changes: 2 additions & 14 deletions builder/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,7 @@ func (b Select) Limit(value interface{}) Select {
panic("loukoum: select builder has limit clause already defined")
}

limit, ok := ToInt64(value)
if !ok || limit <= 0 {
panic("loukoum: limit must be a positive integer")
}

b.query.Limit = stmt.NewLimit(limit)

b.query.Limit = ToLimit(value)
return b
}

Expand All @@ -203,13 +197,7 @@ func (b Select) Offset(value interface{}) Select {
panic("loukoum: select builder has offset clause already defined")
}

offset, ok := ToInt64(value)
if !ok || offset < 0 {
panic("loukoum: offset must be a non-negative integer")
}

b.query.Offset = stmt.NewOffset(offset)

b.query.Offset = ToOffset(value)
return b
}

Expand Down
10 changes: 10 additions & 0 deletions loukoum.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ func Order(column string, option ...types.OrderType) stmt.Order {
return stmt.NewOrder(column, order)
}

// Offset is a wrapper to create a new Offset statement.
func Offset(start int64) stmt.Offset {
return stmt.NewOffset(start)
}

// Limit is a wrapper to create a new Limit statement.
func Limit(count int64) stmt.Limit {
return stmt.NewLimit(count)
}

// And is a wrapper to create a new InfixExpression statement.
func And(left stmt.Expression, right stmt.Expression) stmt.InfixExpression {
return stmt.NewInfixExpression(left, stmt.NewLogicalOperator(types.And), right)
Expand Down
7 changes: 0 additions & 7 deletions stmt/returning.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package stmt

import (
"sort"

"github.com/ulule/loukoum/v3/token"
"github.com/ulule/loukoum/v3/types"
)
Expand All @@ -24,11 +22,6 @@ func (returning Returning) Write(ctx types.Context) {
ctx.Write(token.Returning.String())
ctx.Write(" ")

sort.Slice(returning.Columns, func(i, j int) bool {
return returning.Columns[i].Name < returning.Columns[j].Name ||
returning.Columns[i].Alias < returning.Columns[j].Alias
})

for i := range returning.Columns {
if i > 0 {
ctx.Write(", ")
Expand Down

0 comments on commit d2f4f2d

Please sign in to comment.