diff --git a/go.mod b/go.mod index ba46589a..39ba5ff7 100644 --- a/go.mod +++ b/go.mod @@ -7,3 +7,5 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 ) + +go 1.13 diff --git a/select.go b/select.go index 5853e824..cde38aa7 100644 --- a/select.go +++ b/select.go @@ -286,16 +286,40 @@ func (b SelectBuilder) JoinClause(pred interface{}, args ...interface{}) SelectB return builder.Append(b, "Joins", newPart(pred, args...)).(SelectBuilder) } +// JoinSelect sets a subquery into the Join clause of the query. +func (b SelectBuilder) JoinSelect(from SelectBuilder, alias string, pred interface{}, args ...interface{}) SelectBuilder { + // Prevent misnumbered parameters in nested selects (#183). + from = from.PlaceholderFormat(Question) + b = b.JoinClause("JOIN ") + return builder.Append(b, "Joins", Alias(from, alias), newPart(pred, args...)).(SelectBuilder) +} + // Join adds a JOIN clause to the query. func (b SelectBuilder) Join(join string, rest ...interface{}) SelectBuilder { return b.JoinClause("JOIN "+join, rest...) } +// LeftJoinSelect sets a subquery into the Left Join clause of the query. +func (b SelectBuilder) LeftJoinSelect(from SelectBuilder, alias string, pred interface{}, args ...interface{}) SelectBuilder { + // Prevent misnumbered parameters in nested selects (#183). + from = from.PlaceholderFormat(Question) + b = b.JoinClause("LEFT JOIN ") + return builder.Append(b, "Joins", Alias(from, alias), newPart(pred, args...)).(SelectBuilder) +} + // LeftJoin adds a LEFT JOIN clause to the query. func (b SelectBuilder) LeftJoin(join string, rest ...interface{}) SelectBuilder { return b.JoinClause("LEFT JOIN "+join, rest...) } +// RightJoinSelect sets a subquery into the Left Join clause of the query. +func (b SelectBuilder) RightJoinSelect(from SelectBuilder, alias string, pred interface{}, args ...interface{}) SelectBuilder { + // Prevent misnumbered parameters in nested selects (#183). + from = from.PlaceholderFormat(Question) + b = b.JoinClause("RIGHT JOIN ") + return builder.Append(b, "Joins", Alias(from, alias), newPart(pred, args...)).(SelectBuilder) +} + // RightJoin adds a RIGHT JOIN clause to the query. func (b SelectBuilder) RightJoin(join string, rest ...interface{}) SelectBuilder { return b.JoinClause("RIGHT JOIN "+join, rest...) diff --git a/select_test.go b/select_test.go index baa34ce6..ddd9100b 100644 --- a/select_test.go +++ b/select_test.go @@ -182,6 +182,22 @@ func TestSelectBuilderNestedSelectJoin(t *testing.T) { assert.Equal(t, args, expectedArgs) } +func TestSelectBuilderNestedSelectJoinNew(t *testing.T) { + + expectedSql := "SELECT * FROM bar JOIN (SELECT * FROM baz WHERE foo = ?) AS r ON bar.foo = r.foo" + expectedArgs := []interface{}{42} + + nestedSelect := Select("*").From("baz").Where("foo = ?", 42) + + b := Select("*").From("bar").JoinSelect(nestedSelect, "r", "ON bar.foo = r.foo") + + sql, args, err := b.ToSql() + assert.NoError(t, err) + + assert.Equal(t, expectedSql, sql) + assert.Equal(t, args, expectedArgs) +} + func TestSelectWithOptions(t *testing.T) { sql, _, err := Select("*").From("foo").Distinct().Options("SQL_NO_CACHE").ToSql()