Skip to content

Commit

Permalink
Added goqu.V for #104
Browse files Browse the repository at this point in the history
* [ADDED] `goqu.V` so values can be used on the LHS of expressions #104
  • Loading branch information
doug-martin committed Jul 26, 2019
1 parent 395454a commit 251428a
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 7 deletions.
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## v8.0.1

* [ADDED] Multi table update support for `mysql` and `postgres` [#60](https://github.com/doug-martin/goqu/issues/60)
* [ADDED] `goqu.V` so values can be used on the LHS of expressions [#104](https://github.com/doug-martin/goqu/issues/104)

## v8.0.0

Expand Down
18 changes: 18 additions & 0 deletions dialect/mysql/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,24 @@ func (mt *mysqlTest) TestQuery() {
assert.Len(t, entries, 0)
}

func (mt *mysqlTest) TestQuery_ValueExpressions() {
type wrappedEntry struct {
entry
BoolValue bool `db:"bool_value"`
}
expectedDate, err := time.Parse("2006-01-02 15:04:05", "2015-02-22 19:19:55")
mt.NoError(err)
ds := mt.db.From("entry").Select(goqu.Star(), goqu.V(true).As("bool_value")).Where(goqu.Ex{"int": 1})
var we wrappedEntry
found, err := ds.ScanStruct(&we)
mt.NoError(err)
mt.True(found)
mt.Equal(we, wrappedEntry{
entry{2, 1, 0.100000, "0.100000", expectedDate, false, []byte("0.100000")},
true,
})
}

func (mt *mysqlTest) TestCount() {
t := mt.T()
ds := mt.db.From("entry")
Expand Down
21 changes: 21 additions & 0 deletions dialect/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,27 @@ func (pt *postgresTest) TestQuery() {
assert.Len(t, entries, 0)
}

func (pt *postgresTest) TestQuery_ValueExpressions() {
type wrappedEntry struct {
entry
BoolValue bool `db:"bool_value"`
}
expectedDate, err := time.Parse(time.RFC3339Nano, "2015-02-22T19:19:55.000000000-00:00")
pt.NoError(err)
ds := pt.db.From("entry").Select(goqu.Star(), goqu.V(true).As("bool_value")).Where(goqu.Ex{"int": 1})
var we wrappedEntry
found, err := ds.ScanStruct(&we)
pt.NoError(err)
pt.True(found)
pt.Equal(1, we.Int)
pt.Equal(0.100000, we.Float)
pt.Equal("0.100000", we.String)
pt.Equal(expectedDate.Unix(), we.Time.Unix())
pt.Equal(false, we.Bool)
pt.Equal([]byte("0.100000"), we.Bytes)
pt.True(we.BoolValue)
}

func (pt *postgresTest) TestCount() {
t := pt.T()
ds := pt.db.From("entry")
Expand Down
18 changes: 18 additions & 0 deletions dialect/sqlite3/sqlite3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,24 @@ func (st *sqlite3Suite) TestQuery() {
assert.Len(t, entries, 0)
}

func (st *sqlite3Suite) TestQuery_ValueExpressions() {
type wrappedEntry struct {
entry
BoolValue bool `db:"bool_value"`
}
expectedDate, err := time.Parse("2006-01-02 15:04:05", "2015-02-22 19:19:55")
st.NoError(err)
ds := st.db.From("entry").Select(goqu.Star(), goqu.V(true).As("bool_value")).Where(goqu.Ex{"int": 1})
var we wrappedEntry
found, err := ds.ScanStruct(&we)
st.NoError(err)
st.True(found)
st.Equal(we, wrappedEntry{
entry{2, 1, 0.100000, "0.100000", expectedDate, false, []byte("0.100000")},
true,
})
}

func (st *sqlite3Suite) TestCount() {
t := st.T()
ds := st.db.From("entry")
Expand Down
59 changes: 58 additions & 1 deletion docs/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
* [`T`](#T) - An Identifier that represents a Table. With a Table identifier you can fully qualify columns.
* [`C`](#C) - An Identifier that represents a Column. See the docs for more examples
* [`I`](#I) - An Identifier represents a schema, table, or column or any combination. I parses identifiers seperated by a . character.
* [`L`](#L) - An SQL literal.
* [`L`](#L) - An SQL literal.
* [`V`](#V) - An Value to be used in SQL.
* [`And`](#and) - AND multiple expressions together.
* [`Or`](#or) - OR multiple expressions together.
* [Complex Example] - Complex Example using most of the Expression DSL.
Expand Down Expand Up @@ -201,6 +202,61 @@ SELECT * FROM "test" WHERE ("json"::TEXT = "other_json"::TEXT) AND col IN ('a',
SELECT * FROM "test" WHERE ("json"::TEXT = "other_json"::TEXT) AND col IN ($1, $2, $3) [a, b, c]
```

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

Sometimes you may have a value that you want to use directly in SQL.

**NOTE** This is a shorter version of `goqu.L("?", val)`

For example you may want to select a value as a column.

```go
ds := goqu.From("user").Select(
goqu.V(true).As("is_verified"),
goqu.V(1.2).As("version"),
"first_name",
"last_name",
)

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

Output:
```
SELECT TRUE AS "is_verified", 1.2 AS "version", "first_name", "last_name" FROM "user" []
```

You can also use `goqu.V` in where clauses.

```
ds := goqu.From("user").Where(goqu.V(1).Neq(1))
sql, args, _ := ds.ToSQL()
fmt.Println(sql, args)
```

Output:

```
SELECT * FROM "user" WHERE (1 != 1) []
```

You can also use them in prepared statements.

```
ds := goqu.From("user").Where(goqu.V(1).Neq(1))
sql, args, _ := ds.Prepared(true).ToSQL()
fmt.Println(sql, args)
```

Output:

```
SELECT * FROM "user" WHERE (? != ?) [1, 1]
```


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

Expand Down Expand Up @@ -388,3 +444,4 @@ HAVING (AVG("test3"."age") > ?)
ORDER BY "test"."created" DESC NULLS LAST [^(a|b) passed active registered 10]
```


6 changes: 6 additions & 0 deletions expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ func Literal(sql string, args ...interface{}) exp.LiteralExpression {
return L(sql, args...)
}

// Create a new SQL value ( alias for goqu.L("?", val) ). The prrimary use case for this would be in selects.
// See examples.
func V(val interface{}) exp.LiteralExpression {
return exp.NewLiteralExpression("?", val)
}

// Creates a new Range to be used with a Between expression
// exp.C("col").Between(exp.Range(1, 10))
func Range(start, end interface{}) exp.RangeVal {
Expand Down
41 changes: 41 additions & 0 deletions expressions_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,47 @@ func ExampleRecord_update() {
// UPDATE "test" SET "col1"=?,"col2"=? [1 foo]
}

func ExampleV() {
ds := goqu.From("user").Select(
goqu.V(true).As("is_verified"),
goqu.V(1.2).As("version"),
"first_name",
"last_name",
)

sql, args, _ := ds.ToSQL()
fmt.Println(sql, args)

ds = goqu.From("user").Where(goqu.V(1).Neq(1))
sql, args, _ = ds.ToSQL()
fmt.Println(sql, args)

// Output:
// SELECT TRUE AS "is_verified", 1.2 AS "version", "first_name", "last_name" FROM "user" []
// SELECT * FROM "user" WHERE (1 != 1) []
}

func ExampleV_prepared() {
ds := goqu.From("user").Select(
goqu.V(true).As("is_verified"),
goqu.V(1.2).As("version"),
"first_name",
"last_name",
)

sql, args, _ := ds.Prepared(true).ToSQL()
fmt.Println(sql, args)

ds = goqu.From("user").Where(goqu.V(1).Neq(1))

sql, args, _ = ds.Prepared(true).ToSQL()
fmt.Println(sql, args)

// Output:
// SELECT ? AS "is_verified", ? AS "version", "first_name", "last_name" FROM "user" [true 1.2]
// SELECT * FROM "user" WHERE (? != ?) [1 1]
}

func ExampleVals() {
ds := goqu.Insert("user").
Cols("first_name", "last_name", "is_verified").
Expand Down
6 changes: 0 additions & 6 deletions sql_dialect.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,9 +726,6 @@ func (d *sqlDialect) onConflictSQL(b sb.SQLBuilder, o exp.ConflictExpression) {
}

func (d *sqlDialect) updateTableSQL(b sb.SQLBuilder, uc exp.UpdateClauses) {
if b.Error() != nil {
return
}
b.WriteRunes(d.dialectOptions.SpaceRune)
d.Literal(b, uc.Table())
if b.Error() != nil {
Expand Down Expand Up @@ -758,9 +755,6 @@ func (d *sqlDialect) updateValuesSQL(b sb.SQLBuilder, updates ...exp.UpdateExpre
}

func (d *sqlDialect) updateFromSQL(b sb.SQLBuilder, ce exp.ColumnListExpression) {
if b.Error() != nil {
return
}
if ce == nil || ce.IsEmpty() {
return
}
Expand Down

0 comments on commit 251428a

Please sign in to comment.