diff --git a/HISTORY.md b/HISTORY.md
index e53394e1..56ca9c8f 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -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
diff --git a/dialect/mysql/mysql_test.go b/dialect/mysql/mysql_test.go
index 9086453c..ac19ff14 100644
--- a/dialect/mysql/mysql_test.go
+++ b/dialect/mysql/mysql_test.go
@@ -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")
diff --git a/dialect/postgres/postgres_test.go b/dialect/postgres/postgres_test.go
index 057f2f21..e57b000a 100644
--- a/dialect/postgres/postgres_test.go
+++ b/dialect/postgres/postgres_test.go
@@ -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")
diff --git a/dialect/sqlite3/sqlite3_test.go b/dialect/sqlite3/sqlite3_test.go
index 6976f9e0..9e25108e 100644
--- a/dialect/sqlite3/sqlite3_test.go
+++ b/dialect/sqlite3/sqlite3_test.go
@@ -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")
diff --git a/docs/expressions.md b/docs/expressions.md
index a06682f6..945db00a 100644
--- a/docs/expressions.md
+++ b/docs/expressions.md
@@ -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.
@@ -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]
```
+
+**[`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]
+```
+
+
**[`And()`](https://godoc.org/github.com/doug-martin/goqu#And)**
@@ -388,3 +444,4 @@ HAVING (AVG("test3"."age") > ?)
ORDER BY "test"."created" DESC NULLS LAST [^(a|b) passed active registered 10]
```
+
diff --git a/expressions.go b/expressions.go
index b7a31b76..097efc14 100644
--- a/expressions.go
+++ b/expressions.go
@@ -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 {
diff --git a/expressions_example_test.go b/expressions_example_test.go
index 42b53c06..12449574 100644
--- a/expressions_example_test.go
+++ b/expressions_example_test.go
@@ -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").
diff --git a/sql_dialect.go b/sql_dialect.go
index 63258de3..5cfee69d 100644
--- a/sql_dialect.go
+++ b/sql_dialect.go
@@ -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 {
@@ -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
}