Skip to content

Commit

Permalink
doug-martin#204: support exists expression
Browse files Browse the repository at this point in the history
* add exists expression

* add select_dataset methods

* exists works for non prepared queries

* exists works for non prepared queries

* fixed test with prepared statement

* more expression examples

* expression examples fix
  • Loading branch information
Yakov-Varnaev authored Mar 23, 2024
1 parent 21b6e6d commit f6deabb
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 0 deletions.
4 changes: 4 additions & 0 deletions expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ func All(val interface{}) exp.SQLFunctionExpression {
return Func("ALL ", val)
}

func Exists(val interface{}) exp.SQLFunctionExpression {
return Func("EXISTS ", val)
}

func Case() exp.CaseExpression {
return exp.NewCaseExpression()
}
26 changes: 26 additions & 0 deletions expressions_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1807,6 +1807,32 @@ func ExampleAny() {
// SELECT * FROM "test" WHERE ("id" = ANY ((SELECT "test_id" FROM "other"))) []
}

func ExampleExists() {
ds := goqu.Select(goqu.Exists(goqu.From("test")))
sql, args, _ := ds.ToSQL()
fmt.Println(sql, args)

sql, args, _ = ds.Prepared(true).ToSQL()
fmt.Println(sql, args)
// Output:
// SELECT EXISTS ((SELECT * FROM "test")) []
// SELECT EXISTS ((SELECT * FROM "test")) []
}

func ExampleExists_inWhereClauses() {
ds := goqu.From("test").Where(
goqu.Exists(goqu.From("other").Where(goqu.Ex{"test_id": goqu.I("id")})),
)
sql, args, _ := ds.ToSQL()
fmt.Println(sql, args)

sql, args, _ = ds.Prepared(true).ToSQL()
fmt.Println(sql, args)
// Output:
// SELECT * FROM "test" WHERE EXISTS ((SELECT * FROM "other" WHERE ("test_id" = "id"))) []
// SELECT * FROM "test" WHERE EXISTS ((SELECT * FROM "other" WHERE ("test_id" = "id"))) []
}

func ExampleAll() {
ds := goqu.From("test").Where(goqu.Ex{
"id": goqu.All(goqu.From("other").Select("test_id")),
Expand Down
7 changes: 7 additions & 0 deletions expressions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ func (ges *goquExpressionsSuite) TestAll() {
ges.Equal(exp.NewSQLFunctionExpression("ALL ", ds), goqu.All(ds))
}

func (ges *goquExpressionsSuite) TestExists() {
ds := goqu.From("test").Where(
goqu.Exists(goqu.From("other").Where(goqu.Ex{"test_id": goqu.I("id")})),
)
ges.Equal(exp.NewSQLFunctionExpression("EXISTS ", ds), goqu.Exists(ds))
}

func TestGoquExpressions(t *testing.T) {
suite.Run(t, new(goquExpressionsSuite))
}
12 changes: 12 additions & 0 deletions select_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,18 @@ func (sd *SelectDataset) CountContext(ctx context.Context) (int64, error) {
return count, err
}

// Generates the SELECT EXISTS(...) sql for this dataset and uses Exec#ScanVal to scan the result into an bool.
func (sd *SelectDataset) Exists() (bool, error) {
return sd.ExistsContext(context.Background())
}

// Generates the SELECT EXISTS(...) sql for this dataset and uses Exec#ScanValContext to scan the result into an bool.
func (sd *SelectDataset) ExistsContext(ctx context.Context) (bool, error) {
var exists bool
_, err := newDataset(sd.dialect.Dialect(), sd.queryFactory).Select(Exists(sd)).Prepared(sd.IsPrepared()).ScanValContext(ctx, &exists)
return exists, err
}

// Generates the SELECT sql only selecting the passed in column and uses Exec#ScanVals to scan the result into a slice
// of primitive values.
//
Expand Down
12 changes: 12 additions & 0 deletions select_dataset_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,18 @@ func ExampleSelectDataset_Count() {
// Count is 4
}

func ExampleSelectDataset_Exists() {
exists, err := getDB().From("goqu_user").Exists()
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Printf("Exists is %t", exists)

// Output:
// Exists is true
}

func ExampleSelectDataset_Pluck() {
var lastNames []string
if err := getDB().From("goqu_user").Pluck(&lastNames, "last_name"); err != nil {
Expand Down
31 changes: 31 additions & 0 deletions select_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,37 @@ func (sds *selectDatasetSuite) TestCount_WithPreparedStatement() {
sds.Equal(int64(10), count)
}

func (sds *selectDatasetSuite) TestExists() {
mDB, sqlMock, err := sqlmock.New()
sds.NoError(err)
sqlMock.ExpectQuery(`SELECT EXISTS \(\(SELECT \* FROM "items"\)\) LIMIT 1`).
WithArgs().
WillReturnRows(sqlmock.NewRows([]string{"exists"}).FromCSVString("true"))

db := goqu.New("mock", mDB)
exists, err := db.From("items").Exists()
sds.NoError(err)
sds.True(exists)
}

func (sds *selectDatasetSuite) TestExists_WithPreparedStatement() {
mDB, sqlMock, err := sqlmock.New()
sds.NoError(err)
sqlMock.ExpectQuery(
`SELECT EXISTS \(\(SELECT \* FROM "items" WHERE \("address" = \?\)\)\) LIMIT \?`,
).
WithArgs("111 Test Addr", 1).
WillReturnRows(sqlmock.NewRows([]string{"exists"}).FromCSVString("true"))

ds := goqu.New("mock", mDB)
exists, err := ds.From("items").
Prepared(true).
Where(goqu.Ex{"address": "111 Test Addr"}).
Exists()
sds.NoError(err)
sds.True(exists)
}

func (sds *selectDatasetSuite) TestPluck() {
mDB, sqlMock, err := sqlmock.New()
sds.NoError(err)
Expand Down

0 comments on commit f6deabb

Please sign in to comment.