Skip to content

Commit

Permalink
merge scope WHERE
Browse files Browse the repository at this point in the history
  • Loading branch information
Mario L Gutierrez committed Jun 17, 2015
1 parent 2aa5d31 commit 63b12b7
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 20 deletions.
23 changes: 23 additions & 0 deletions scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,26 @@ func escapeScopeTable(sql string, table string) string {
quoted := buf.String()
return strings.Replace(sql, ":TABLE", quoted, -1)
}

var reWhereClause = regexp.MustCompile(`\s*(WHERE|where)\b`)

// splitWhere splits a query on the word WHERE
func splitWhere(query string) (sql string, where string) {
indices := reWhereClause.FindStringIndex(query)
// grab only the first location
if len(indices) == 0 {
return query, ""
}

// may have leading spaces
where = query[indices[0]:]
idx := strings.Index(where, "WHERE")
if idx == -1 {
idx = strings.Index(where, "where")
}
// 5 == len("WHERE")
where = where[idx+5:]

sql = query[0:indices[0]]
return sql, where
}
24 changes: 14 additions & 10 deletions select.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (b *SelectBuilder) Distinct() *SelectBuilder {
return b
}

// From sets the table to SELECT FROM
// From sets the table to SELECT FROM. JOINs may also be defined here.
func (b *SelectBuilder) From(from string) *SelectBuilder {
b.table = from
return b
Expand All @@ -49,7 +49,7 @@ func (b *SelectBuilder) ScopeMap(mapScope *MapScope, m M) *SelectBuilder {
// Scope uses a predefined scope in place of WHERE.
func (b *SelectBuilder) Scope(sql string, args ...interface{}) *SelectBuilder {
b.scope = ScopeFunc(func(table string) (string, []interface{}) {
return escapeScopeTable(sql, table), args
return sql, args
})
return b
}
Expand Down Expand Up @@ -132,14 +132,18 @@ func (b *SelectBuilder) ToSQL() (string, []interface{}) {
buf.WriteString(b.table)

var placeholderStartPos int64 = 1
if b.scope == nil {
if len(b.whereFragments) > 0 {
buf.WriteString(" WHERE ")
writeWhereFragmentsToSql(buf, b.whereFragments, &args, &placeholderStartPos)
}
} else {
whereFragment := newWhereFragment(b.scope.ToSQL(b.table))
writeScopeCondition(buf, whereFragment, &args, &placeholderStartPos)
if b.scope != nil {
var where string
sql, args := b.scope.ToSQL(b.table)
sql, where = splitWhere(sql)
buf.WriteString(sql)
fragment := newWhereFragment(where, args)
b.whereFragments = append(b.whereFragments, fragment)
}

if len(b.whereFragments) > 0 {
buf.WriteString(" WHERE ")
writeWhereFragmentsToSql(buf, b.whereFragments, &args, &placeholderStartPos)
}

if len(b.groupBys) > 0 {
Expand Down
19 changes: 18 additions & 1 deletion select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func TestSelectVarieties(t *testing.T) {
func TestSelectScope(t *testing.T) {
scope := NewScope("WHERE :TABLE.id = :id and name = :name", M{"id": 1, "name": "foo"})
sql, args := Select("a").From("b").ScopeMap(scope, M{"name": "mario"}).ToSQL()
assert.Equal(t, sql, `SELECT a FROM b WHERE "b".id = $1 and name = $2`)
assert.Equal(t, `SELECT a FROM b WHERE ( "b".id = $1 and name = $2)`, sql)
assert.Exactly(t, args, []interface{}{1, "mario"})
}

Expand All @@ -223,3 +223,20 @@ func TestInnerJoin(t *testing.T) {
assert.Equal(t, sql, "SELECT u.*, p.* FROM users u INNER JOIN posts p on (p.author_id = u.id) WHERE (u.id = $1)")
assert.Exactly(t, args, []interface{}{1})
}

func TestScopeWhere(t *testing.T) {
published := `
INNER JOIN posts p on (p.author_id = u.id)
WHERE
p.state = $1
`

sql, args := Select("u.*, p.*").
From(`users u`).
Scope(published, "published").
Where(`u.id = $1`, 1).
ToSQL()
sql = str.Clean(sql)
assert.Equal(t, "SELECT u.*, p.* FROM users u INNER JOIN posts p on (p.author_id = u.id) WHERE (u.id = $1) AND ( p.state = $2 )", sql)
assert.Exactly(t, args, []interface{}{1, "published"})
}
18 changes: 9 additions & 9 deletions sqlx-runner/select_exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,11 @@ func TestSelectScope(t *testing.T) {
assert.True(t, postID > 0)

publishedByUser := `
INNER JOIN people P on (P.id = :TABLE.user_id)
INNER JOIN people P on (P.id = posts.user_id)
WHERE
P.name = $1 AND
:TABLE.state = 'published' AND
:TABLE.deleted_at IS NULL
posts.state = 'published' AND
posts.deleted_at IS NULL
`
var posts []*Post
err = s.
Expand Down Expand Up @@ -261,17 +261,17 @@ func TestSelectScoped(t *testing.T) {
assert.True(t, postID > 0)

publishedByUser := `
INNER JOIN people P on (P.id = :TABLE.user_id)
INNER JOIN people on (people.id = p.user_id)
WHERE
P.name = $1 AND
:TABLE.state = 'published' AND
:TABLE.deleted_at IS NULL
people.name = $1 AND
p.state = 'published' AND
p.deleted_at IS NULL
`

var posts []*Post
err = s.
Select("posts.*").
From("posts").
Select("p.*").
From("posts p").
Scope(publishedByUser, "mgutz").
QueryStructs(&posts)
assert.NoError(t, err)
Expand Down

0 comments on commit 63b12b7

Please sign in to comment.