Skip to content

Commit

Permalink
Merge pull request #152 from marshallmcmullen/to_error
Browse files Browse the repository at this point in the history
Add Error and SetError to all datasets.
  • Loading branch information
doug-martin authored Sep 6, 2019
2 parents b6f0a15 + ce6df72 commit 26b887b
Show file tree
Hide file tree
Showing 14 changed files with 526 additions and 16 deletions.
21 changes: 21 additions & 0 deletions delete_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type DeleteDataset struct {
clauses exp.DeleteClauses
isPrepared bool
queryFactory exec.QueryFactory
err error
}

// used internally by database to create a database with a specific adapter
Expand Down Expand Up @@ -74,6 +75,7 @@ func (dd *DeleteDataset) copy(clauses exp.DeleteClauses) *DeleteDataset {
clauses: clauses,
isPrepared: dd.isPrepared,
queryFactory: dd.queryFactory,
err: dd.err,
}
}

Expand Down Expand Up @@ -170,6 +172,22 @@ func (dd *DeleteDataset) Returning(returning ...interface{}) *DeleteDataset {
return dd.copy(dd.clauses.SetReturning(exp.NewColumnListExpression(returning...)))
}

// Get any error that has been set or nil if no error has been set.
func (dd *DeleteDataset) Error() error {
return dd.err
}

// Set an error on the dataset if one has not already been set. This error will be returned by a future call to Error
// or as part of ToSQL. This can be used by end users to record errors while building up queries without having to
// track those separately.
func (dd *DeleteDataset) SetError(err error) *DeleteDataset {
if dd.err == nil {
dd.err = err
}

return dd
}

// Generates a DELETE sql statement, if Prepared has been called with true then the parameters will not be interpolated.
// See examples.
//
Expand All @@ -189,6 +207,9 @@ func (dd *DeleteDataset) Executor() exec.QueryExecutor {

func (dd *DeleteDataset) deleteSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(dd.isPrepared)
if dd.err != nil {
return buf.SetError(dd.err)
}
dd.dialect.ToDeleteSQL(buf, dd.clauses)
return buf
}
45 changes: 45 additions & 0 deletions delete_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,51 @@ func (dds *deleteDatasetSuite) TestExecutor() {
dds.Equal(`DELETE FROM "items" WHERE ("id" > ?)`, dsql)
}

func (dds *deleteDatasetSuite) TestSetError() {

err1 := errors.New("error #1")
err2 := errors.New("error #2")
err3 := errors.New("error #3")

// Verify initial error set/get works properly
md := new(mocks.SQLDialect)
ds := Delete("test").SetDialect(md)
ds = ds.SetError(err1)
dds.Equal(err1, ds.Error())
sql, args, err := ds.ToSQL()
dds.Empty(sql)
dds.Empty(args)
dds.Equal(err1, err)

// Repeated SetError calls on Dataset should not overwrite the original error
ds = ds.SetError(err2)
dds.Equal(err1, ds.Error())
sql, args, err = ds.ToSQL()
dds.Empty(sql)
dds.Empty(args)
dds.Equal(err1, err)

// Builder functions should not lose the error
ds = ds.ClearLimit()
dds.Equal(err1, ds.Error())
sql, args, err = ds.ToSQL()
dds.Empty(sql)
dds.Empty(args)
dds.Equal(err1, err)

// Deeper errors inside SQL generation should still return original error
c := ds.GetClauses()
sqlB := sb.NewSQLBuilder(false)
md.On("ToDeleteSQL", sqlB, c).Run(func(args mock.Arguments) {
args.Get(0).(sb.SQLBuilder).SetError(err3)
}).Once()

sql, args, err = ds.ToSQL()
dds.Empty(sql)
dds.Empty(args)
dds.Equal(err1, err)
}

func TestDeleteDataset(t *testing.T) {
suite.Run(t, new(deleteDatasetSuite))
}
52 changes: 49 additions & 3 deletions docs/deleting.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
* [Order](#order)
* [Limit](#limit)
* [Returning](#returning)
* [SetError](#seterror)
* [Executing](#exec)
<a name="create"></a>

<a name="create"></a>
To create a [`DeleteDataset`](https://godoc.org/github.com/doug-martin/goqu/#DeleteDataset) you can use

**[`goqu.Delete`](https://godoc.org/github.com/doug-martin/goqu/#Delete)**
Expand Down Expand Up @@ -214,6 +215,51 @@ Output:
DELETE FROM "test" RETURNING "test".*
```

<a name="seterror"></a>
**[`SetError`](https://godoc.org/github.com/doug-martin/goqu/#DeleteDataset.SetError)**

Sometimes while building up a query with goqu you will encounter situations where certain
preconditions are not met or some end-user contraint has been violated. While you could
track this error case separately, goqu provides a convenient built-in mechanism to set an
error on a dataset if one has not already been set to simplify query building.

Set an Error on a dataset:

```go
func GetDelete(name string, value string) *goqu.DeleteDataset {

var ds = goqu.Delete("test")

if len(name) == 0 {
return ds.SetError(fmt.Errorf("name is empty"))
}

if len(value) == 0 {
return ds.SetError(fmt.Errorf("value is empty"))
}

return ds.Where(goqu.C(name).Eq(value))
}

```

This error is returned on any subsequent call to `Error` or `ToSQL`:

```go
var field, value string
ds = GetDelete(field, value)
fmt.Println(ds.Error())

sql, args, err = ds.ToSQL()
fmt.Println(err)
```

Output:
```
name is empty
name is empty
```

## Executing Deletes

To execute DELETES use [`Database.Delete`](https://godoc.org/github.com/doug-martin/goqu/#Database.Delete) to create your dataset
Expand Down Expand Up @@ -265,4 +311,4 @@ Output:

```
Deleted users [ids:=[1 2 3]]
```
```
54 changes: 50 additions & 4 deletions docs/inserting.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
* [Insert Map](#insert-map)
* [Insert From Query](#insert-from-query)
* [Returning](#returning)
* [SetError](#seterror)
* [Executing](#executing)
<a name="create"></a>

<a name="create"></a>
To create a [`InsertDataset`](https://godoc.org/github.com/doug-martin/goqu/#InsertDataset) you can use

**[`goqu.Insert`](https://godoc.org/github.com/doug-martin/goqu/#Insert)**
Expand Down Expand Up @@ -109,7 +110,7 @@ insertSQL, args, _ := ds.ToSQL()
fmt.Println(insertSQL, args)
```

Output:
Output:
```sql
INSERT INTO "user" ("first_name", "last_name") VALUES ('Greg', 'Farley'), ('Jimmy', 'Stewart'), ('Jeff', 'Jeffers') []
```
Expand Down Expand Up @@ -373,6 +374,51 @@ Output:
INSERT INTO "test" ("a", "b") VALUES ('a', 'b') RETURNING "test".*
```

<a name="seterror"></a>
**[`SetError`](https://godoc.org/github.com/doug-martin/goqu/#InsertDataset.SetError)**

Sometimes while building up a query with goqu you will encounter situations where certain
preconditions are not met or some end-user contraint has been violated. While you could
track this error case separately, goqu provides a convenient built-in mechanism to set an
error on a dataset if one has not already been set to simplify query building.

Set an Error on a dataset:

```go
func GetInsert(name string, value string) *goqu.InsertDataset {

var ds = goqu.Insert("test")

if len(field) == 0 {
return ds.SetError(fmt.Errorf("name is empty"))
}

if len(value) == 0 {
return ds.SetError(fmt.Errorf("value is empty"))
}

return ds.Rows(goqu.Record{name: value})
}

```

This error is returned on any subsequent call to `Error` or `ToSQL`:

```go
var field, value string
ds = GetInsert(field, value)
fmt.Println(ds.Error())

sql, args, err = ds.ToSQL()
fmt.Println(err)
```

Output:
```
name is empty
name is empty
```

<a name="executing"></a>
## Executing Inserts

Expand Down Expand Up @@ -447,4 +493,4 @@ Output:

```
Inserted 1 user id:=5
```
```
52 changes: 47 additions & 5 deletions docs/selecting.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* [`GroupBy`](#group_by)
* [`Having`](#having)
* [`Window`](#window)
* [`SetError`](#seterror)
* Executing Queries
* [`ScanStructs`](#scan-structs) - Scans rows into a slice of structs
* [`ScanStruct`](#scan-struct) - Scans a row into a slice a struct, returns false if a row wasnt found
Expand All @@ -20,7 +21,7 @@
* [`Count`](#count) - Returns the count for the current query
* [`Pluck`](#pluck) - Selects a single column and stores the results into a slice of primitive values

<a name="create"></a>
<a name="create"></a>
To create a [`SelectDataset`](https://godoc.org/github.com/doug-martin/goqu/#SelectDataset) you can use

**[`goqu.From`](https://godoc.org/github.com/doug-martin/goqu/#From) and [`goqu.Select`](https://godoc.org/github.com/doug-martin/goqu/#Select)**
Expand Down Expand Up @@ -95,7 +96,7 @@ sql, _, _ := goqu.From("test").Select("a", "b", "c").ToSQL()
fmt.Println(sql)
```

Output:
Output:
```sql
SELECT "a", "b", "c" FROM "test"
```
Expand Down Expand Up @@ -647,12 +648,53 @@ Output:
SELECT ROW_NUMBER() OVER "w" FROM "test" WINDOW "w" AS (PARTITION BY "a" ORDER BY "b")
```

<a name="seterror"></a>
**[`SetError`](https://godoc.org/github.com/doug-martin/goqu/#SelectDataset.SetError)**

Sometimes while building up a query with goqu you will encounter situations where certain
preconditions are not met or some end-user contraint has been violated. While you could
track this error case separately, goqu provides a convenient built-in mechanism to set an
error on a dataset if one has not already been set to simplify query building.

Set an Error on a dataset:

```go
func GetSelect(name string) *goqu.SelectDataset {

var ds = goqu.From("test")

if len(name) == 0 {
return ds.SetError(fmt.Errorf("name is empty"))
}

return ds.Select(name)
}

```

This error is returned on any subsequent call to `Error` or `ToSQL`:

```go
var name string = ""
ds = GetSelect(name)
fmt.Println(ds.Error())

sql, args, err = ds.ToSQL()
fmt.Println(err)
```

Output:
```
name is empty
name is empty
```

## Executing Queries

To execute your query use [`goqu.Database#From`](https://godoc.org/github.com/doug-martin/goqu/#Database.From) to create your dataset

<a name="scan-structs"></a>
**[`ScanStructs`](http://godoc.org/github.com/doug-martin/goqu#SelectDataset.ScanStructs)**
**[`ScanStructs`](http://godoc.org/github.com/doug-martin/goqu#SelectDataset.ScanStructs)**

Scans rows into a slice of structs

Expand Down Expand Up @@ -742,7 +784,7 @@ fmt.Printf("\n%+v", ids)
<a name="scan-val"></a>
[`ScanVal`](http://godoc.org/github.com/doug-martin/goqu#SelectDataset.ScanVal)

Scans a row of 1 column into a primitive value, returns false if a row wasnt found.
Scans a row of 1 column into a primitive value, returns false if a row wasnt found.

**Note** when using the dataset a `LIMIT` of 1 is automatically applied.
```go
Expand Down Expand Up @@ -774,7 +816,7 @@ fmt.Printf("\nCount:= %d", count)
```

<a name="pluck"></a>
**[`Pluck`](http://godoc.org/github.com/doug-martin/goqu#SelectDataset.Pluck)**
**[`Pluck`](http://godoc.org/github.com/doug-martin/goqu#SelectDataset.Pluck)**

Selects a single column and stores the results into a slice of primitive values

Expand Down
Loading

0 comments on commit 26b887b

Please sign in to comment.