Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Error and SetError to all datasets. #152

Merged
merged 4 commits into from
Sep 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is pedantic but I think it makes sense to put the validation before setting the where. In the end it wont make a difference based on the implementation; but setting the error before creating the clause signifies intention.

I often struggle with showing intention vs how its actually implemented, but in this case validation should come first.

If you disagree let me know, but I want docs to demonstrate how it should be used and not necessarily how it could be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree. I didn't spend a ton of time thinking about the examples from that perspective but you're totally right. I'll push an update. Let me know if you find other things that are confusing.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for being so receptive to comments! I think the same applies for the rest of the examples (they all seem to be based off of this example). Should be a quick update that will helps many users in the long run.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once you update Ill merge update history and release!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely! Yes, I copy-pasted this example to the others and made edits where necessary.

I'll fix the other examples too.

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