Skip to content

Commit

Permalink
Add Union method
Browse files Browse the repository at this point in the history
  • Loading branch information
leporo committed Sep 11, 2019
1 parent 5a17b38 commit 4955695
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 1 deletion.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ Use `SubQuery` method to add a sub query to a statement:
q.Close()
```

Not that if a subquery uses no arguments, it's more effective to add it as SQL fragment:
Note that if a subquery uses no arguments, it's more effective to add it as SQL fragment:

```go
q := sqlf.From("orders o").
Expand All @@ -241,6 +241,21 @@ Not that if a subquery uses no arguments, it's more effective to add it as SQL f
q.Close()
```

#### Unions

Use `Union` method to combine results of two queries:

```go
q := sqlf.From("tasks").
Select("id, status").
Where("status = ?", "new").
Union(false, sqlf.PostgreSQL.From("tasks").
Select("id, status").
Where("status = ?", "wip"))
// ...
q.Close()
```

### INSERT

`sqlf` provides a `Set` method to be used both for UPDATE and INSERT statements:
Expand Down
20 changes: 20 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,23 @@ func ExampleStmt_In() {
// SELECT id, status FROM tasks WHERE status IN (?,?,?)
// [new pending wip]
}

func ExampleStmt_Union() {
q := sqlf.From("tasks").
Select("id, status").
Where("status = ?", "new").
Union(true, sqlf.From("tasks").
Select("id, status").
Where("status = ?", "pending")).
Union(true, sqlf.From("tasks").
Select("id, status").
Where("status = ?", "wip")).
OrderBy("id")
fmt.Println(q.String())
fmt.Println(q.Args())
q.Close()

// Output:
// SELECT id, status FROM tasks WHERE status = ? UNION ALL SELECT id, status FROM tasks WHERE status = ? UNION ALL SELECT id, status FROM tasks WHERE status = ? ORDER BY id
// [new pending wip]
}
36 changes: 36 additions & 0 deletions stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,41 @@ func (q *Stmt) SubQuery(prefix, suffix string, query *Stmt) *Stmt {
return q
}

/*
Union adds a UNION clause to the statement.
all argument controls if UNION ALL or UNION clause
is to be constructed. Use UNION ALL if possible to
get faster queries.
*/
func (q *Stmt) Union(all bool, query *Stmt) *Stmt {
p := posUnion
if len(q.chunks) > 0 {
last := (&q.chunks[len(q.chunks)-1]).pos
if last >= p {
p = last + 1
}
}
var index int
if all {
index = q.addChunk(p, "UNION ALL ", "", query.args, "")
} else {
index = q.addChunk(p, "UNION ", "", query.args, "")
}
chunk := &q.chunks[index]
// Make sure subquery is not dialect-specific.
if query.dialect != NoDialect {
query.dialect = NoDialect
query.Invalidate()
}
q.buf.WriteString(query.String())
chunk.bufHigh = q.buf.Len()
// Close the subquery
query.Close()

return q
}

/*
Clause appends a raw SQL fragment to the statement.
Expand Down Expand Up @@ -725,6 +760,7 @@ const (
posWhere
posGroupBy
posHaving
posUnion
posOrderBy
posLimit
posOffset
Expand Down
11 changes: 11 additions & 0 deletions stmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,14 @@ func TestFullJoin(t *testing.T) {
defer q.Close()
assert.Equal(t, "SELECT id FROM orders o FULL JOIN users u ON (u.id = o.user_id)", q.String())
}

func TestUnion(t *testing.T) {
q := sqlf.From("tasks").
Select("id, status").
Where("status = ?", "new").
Union(false, sqlf.PostgreSQL.From("tasks").
Select("id, status").
Where("status = ?", "wip"))
defer q.Close()
assert.Equal(t, "SELECT id, status FROM tasks WHERE status = ? UNION SELECT id, status FROM tasks WHERE status = ?", q.String())
}

0 comments on commit 4955695

Please sign in to comment.