Skip to content

Commit

Permalink
fix: placeholder sequence
Browse files Browse the repository at this point in the history
  • Loading branch information
ycalansy committed Oct 12, 2022
1 parent 09f5337 commit 2cfc5b8
Show file tree
Hide file tree
Showing 14 changed files with 188 additions and 78 deletions.
2 changes: 1 addition & 1 deletion case.go
Expand Up @@ -27,7 +27,7 @@ func (b *sqlizerBuffer) WriteSql(item Sqlizer) {

var str string
var args []interface{}
str, args, b.err = nestedToSql(item)
str, args, b.err = item.ToSql()

if b.err != nil {
return
Expand Down
32 changes: 29 additions & 3 deletions delete.go
Expand Up @@ -79,7 +79,17 @@ func (d *deleteData) ToSql() (sqlStr string, args []interface{}, err error) {
}
}

sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
sqlStr = sql.String()

return
}

func (d *deleteData) FinalizeSql() (sqlStr string, args []interface{}, err error) {
sqlStr, args, err = d.ToSql()
if err != nil {
return
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
return
}

Expand Down Expand Up @@ -115,13 +125,19 @@ func (b DeleteBuilder) Exec() (sql.Result, error) {

// SQL methods

// ToSql builds the query into a SQL string and bound args.
// ToSql builds the query into a SQL string.
func (b DeleteBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(deleteData)
return data.ToSql()
}

// MustSql builds the query into a SQL string and bound args.
// FinalizeSql builds the query into a SQL string and bound args.
func (b DeleteBuilder) FinalizeSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(deleteData)
return data.FinalizeSql()
}

// MustSql builds the query into a SQL string.
// It panics if there are any errors.
func (b DeleteBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
Expand All @@ -131,6 +147,16 @@ func (b DeleteBuilder) MustSql() (string, []interface{}) {
return sql, args
}

// MustFinalizeSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b DeleteBuilder) MustFinalizeSql() (string, []interface{}) {
sql, args, err := b.FinalizeSql()
if err != nil {
panic(err)
}
return sql, args
}

// Prefix adds an expression to the beginning of the query
func (b DeleteBuilder) Prefix(sql string, args ...interface{}) DeleteBuilder {
return b.PrefixExpr(Expr(sql, args...))
Expand Down
4 changes: 2 additions & 2 deletions delete_test.go
Expand Up @@ -46,10 +46,10 @@ func TestDeleteBuilderMustSql(t *testing.T) {
func TestDeleteBuilderPlaceholders(t *testing.T) {
b := Delete("test").Where("x = ? AND y = ?", 1, 2)

sql, _, _ := b.PlaceholderFormat(Question).ToSql()
sql, _, _ := b.PlaceholderFormat(Question).FinalizeSql()
assert.Equal(t, "DELETE FROM test WHERE x = ? AND y = ?", sql)

sql, _, _ = b.PlaceholderFormat(Dollar).ToSql()
sql, _, _ = b.PlaceholderFormat(Dollar).FinalizeSql()
assert.Equal(t, "DELETE FROM test WHERE x = $1 AND y = $2", sql)
}

Expand Down
40 changes: 26 additions & 14 deletions expr.go
Expand Up @@ -23,7 +23,8 @@ type expr struct {
// Expr builds an expression from a SQL fragment and arguments.
//
// Ex:
// Expr("FROM_UNIXTIME(?)", t)
//
// Expr("FROM_UNIXTIME(?)", t)
func Expr(sql string, args ...interface{}) Sqlizer {
return expr{sql: sql, args: args}
}
Expand Down Expand Up @@ -105,8 +106,9 @@ func (ce concatExpr) ToSql() (sql string, args []interface{}, err error) {
// ConcatExpr builds an expression by concatenating strings and other expressions.
//
// Ex:
// name_expr := Expr("CONCAT(?, ' ', ?)", firstName, lastName)
// ConcatExpr("COALESCE(full_name,", name_expr, ")")
//
// name_expr := Expr("CONCAT(?, ' ', ?)", firstName, lastName)
// ConcatExpr("COALESCE(full_name,", name_expr, ")")
func ConcatExpr(parts ...interface{}) concatExpr {
return concatExpr(parts)
}
Expand All @@ -120,7 +122,8 @@ type aliasExpr struct {
// Alias allows to define alias for column in SelectBuilder. Useful when column is
// defined as complex expression like IF or CASE
// Ex:
// .Column(Alias(caseStmt, "case_column"))
//
// .Column(Alias(caseStmt, "case_column"))
func Alias(expr Sqlizer, alias string) aliasExpr {
return aliasExpr{expr, alias}
}
Expand Down Expand Up @@ -212,7 +215,8 @@ func (eq Eq) ToSql() (sql string, args []interface{}, err error) {

// NotEq is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(NotEq{"id": 1}) == "id <> 1"
//
// .Where(NotEq{"id": 1}) == "id <> 1"
type NotEq Eq

func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -221,7 +225,8 @@ func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {

// Like is syntactic sugar for use with LIKE conditions.
// Ex:
// .Where(Like{"name": "%irrel"})
//
// .Where(Like{"name": "%irrel"})
type Like map[string]interface{}

func (lk Like) toSql(opr string) (sql string, args []interface{}, err error) {
Expand Down Expand Up @@ -260,7 +265,8 @@ func (lk Like) ToSql() (sql string, args []interface{}, err error) {

// NotLike is syntactic sugar for use with LIKE conditions.
// Ex:
// .Where(NotLike{"name": "%irrel"})
//
// .Where(NotLike{"name": "%irrel"})
type NotLike Like

func (nlk NotLike) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -269,7 +275,8 @@ func (nlk NotLike) ToSql() (sql string, args []interface{}, err error) {

// ILike is syntactic sugar for use with ILIKE conditions.
// Ex:
// .Where(ILike{"name": "sq%"})
//
// .Where(ILike{"name": "sq%"})
type ILike Like

func (ilk ILike) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -278,7 +285,8 @@ func (ilk ILike) ToSql() (sql string, args []interface{}, err error) {

// NotILike is syntactic sugar for use with ILIKE conditions.
// Ex:
// .Where(NotILike{"name": "sq%"})
//
// .Where(NotILike{"name": "sq%"})
type NotILike Like

func (nilk NotILike) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -287,7 +295,8 @@ func (nilk NotILike) ToSql() (sql string, args []interface{}, err error) {

// Lt is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(Lt{"id": 1})
//
// .Where(Lt{"id": 1})
type Lt map[string]interface{}

func (lt Lt) toSql(opposite, orEq bool) (sql string, args []interface{}, err error) {
Expand Down Expand Up @@ -339,7 +348,8 @@ func (lt Lt) ToSql() (sql string, args []interface{}, err error) {

// LtOrEq is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(LtOrEq{"id": 1}) == "id <= 1"
//
// .Where(LtOrEq{"id": 1}) == "id <= 1"
type LtOrEq Lt

func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -348,7 +358,8 @@ func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err error) {

// Gt is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(Gt{"id": 1}) == "id > 1"
//
// .Where(Gt{"id": 1}) == "id > 1"
type Gt Lt

func (gt Gt) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -357,7 +368,8 @@ func (gt Gt) ToSql() (sql string, args []interface{}, err error) {

// GtOrEq is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(GtOrEq{"id": 1}) == "id >= 1"
//
// .Where(GtOrEq{"id": 1}) == "id >= 1"
type GtOrEq Lt

func (gtOrEq GtOrEq) ToSql() (sql string, args []interface{}, err error) {
Expand All @@ -372,7 +384,7 @@ func (c conj) join(sep, defaultExpr string) (sql string, args []interface{}, err
}
var sqlParts []string
for _, sqlizer := range c {
partSQL, partArgs, err := nestedToSql(sqlizer)
partSQL, partArgs, err := sqlizer.ToSql()
if err != nil {
return "", nil, err
}
Expand Down
32 changes: 29 additions & 3 deletions insert.go
Expand Up @@ -110,7 +110,17 @@ func (d *insertData) ToSql() (sqlStr string, args []interface{}, err error) {
}
}

sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
sqlStr = sql.String()

return
}

func (d *insertData) FinalizeSql() (sqlStr string, args []interface{}, err error) {
sqlStr, args, err = d.ToSql()
if err != nil {
return
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
return
}

Expand Down Expand Up @@ -210,13 +220,19 @@ func (b InsertBuilder) Scan(dest ...interface{}) error {

// SQL methods

// ToSql builds the query into a SQL string and bound args.
// ToSql builds the query into a SQL string.
func (b InsertBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(insertData)
return data.ToSql()
}

// MustSql builds the query into a SQL string and bound args.
// FinalizeSql builds the query into a SQL string and bound args.
func (b InsertBuilder) FinalizeSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(insertData)
return data.FinalizeSql()
}

// MustSql builds the query into a SQL string.
// It panics if there are any errors.
func (b InsertBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
Expand All @@ -226,6 +242,16 @@ func (b InsertBuilder) MustSql() (string, []interface{}) {
return sql, args
}

// MustFinalizeSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b InsertBuilder) MustFinalizeSql() (string, []interface{}) {
sql, args, err := b.FinalizeSql()
if err != nil {
panic(err)
}
return sql, args
}

// Prefix adds an expression to the beginning of the query
func (b InsertBuilder) Prefix(sql string, args ...interface{}) InsertBuilder {
return b.PrefixExpr(Expr(sql, args...))
Expand Down
4 changes: 2 additions & 2 deletions insert_test.go
Expand Up @@ -49,10 +49,10 @@ func TestInsertBuilderMustSql(t *testing.T) {
func TestInsertBuilderPlaceholders(t *testing.T) {
b := Insert("test").Values(1, 2)

sql, _, _ := b.PlaceholderFormat(Question).ToSql()
sql, _, _ := b.PlaceholderFormat(Question).FinalizeSql()
assert.Equal(t, "INSERT INTO test VALUES (?,?)", sql)

sql, _, _ = b.PlaceholderFormat(Dollar).ToSql()
sql, _, _ = b.PlaceholderFormat(Dollar).FinalizeSql()
assert.Equal(t, "INSERT INTO test VALUES ($1,$2)", sql)
}

Expand Down
10 changes: 1 addition & 9 deletions part.go
Expand Up @@ -29,17 +29,9 @@ func (p part) ToSql() (sql string, args []interface{}, err error) {
return
}

func nestedToSql(s Sqlizer) (string, []interface{}, error) {
if raw, ok := s.(rawSqlizer); ok {
return raw.toSqlRaw()
} else {
return s.ToSql()
}
}

func appendToSql(parts []Sqlizer, w io.Writer, sep string, args []interface{}) ([]interface{}, error) {
for i, p := range parts {
partSql, partArgs, err := nestedToSql(p)
partSql, partArgs, err := p.ToSql()
if err != nil {
return nil, err
} else if len(partSql) == 0 {
Expand Down
41 changes: 31 additions & 10 deletions select.go
Expand Up @@ -55,13 +55,7 @@ func (d *selectData) QueryRow() RowScanner {
}

func (d *selectData) ToSql() (sqlStr string, args []interface{}, err error) {
sqlStr, args, err = d.toSqlRaw()
if err != nil {
return
}

sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
return
return d.toSqlRaw()
}

func (d *selectData) toSqlRaw() (sqlStr string, args []interface{}, err error) {
Expand Down Expand Up @@ -188,6 +182,16 @@ func (d *selectData) toSqlRaw() (sqlStr string, args []interface{}, err error) {
return
}

func (d *selectData) FinalizeSql() (sqlStr string, args []interface{}, err error) {
sqlStr, args, err = d.toSqlRaw()
if err != nil {
return
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
return

}

// Builder

// SelectBuilder builds SQL SELECT statements.
Expand Down Expand Up @@ -240,7 +244,7 @@ func (b SelectBuilder) Scan(dest ...interface{}) error {

// SQL methods

// ToSql builds the query into a SQL string and bound args.
// ToSql builds the query into a SQL string.
func (b SelectBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(selectData)
return data.ToSql()
Expand All @@ -251,7 +255,13 @@ func (b SelectBuilder) toSqlRaw() (string, []interface{}, error) {
return data.toSqlRaw()
}

// MustSql builds the query into a SQL string and bound args.
// FinalizeSql builds the query into a SQL string and bound args.
func (b SelectBuilder) FinalizeSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(selectData)
return data.FinalizeSql()
}

// MustSql builds the query into a SQL string.
// It panics if there are any errors.
func (b SelectBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
Expand All @@ -261,6 +271,16 @@ func (b SelectBuilder) MustSql() (string, []interface{}) {
return sql, args
}

// MustFinalizeSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b SelectBuilder) MustFinalizeSql() (string, []interface{}) {
sql, args, err := b.FinalizeSql()
if err != nil {
panic(err)
}
return sql, args
}

// Prefix adds an expression to the beginning of the query
func (b SelectBuilder) Prefix(sql string, args ...interface{}) SelectBuilder {
return b.PrefixExpr(Expr(sql, args...))
Expand Down Expand Up @@ -309,7 +329,8 @@ func (b SelectBuilder) Columns(columns ...string) SelectBuilder {
// Column adds a result column to the query.
// Unlike Columns, Column accepts args which will be bound to placeholders in
// the columns string, for example:
// Column("IF(col IN ("+squirrel.Placeholders(3)+"), 1, 0) as col", 1, 2, 3)
//
// Column("IF(col IN ("+squirrel.Placeholders(3)+"), 1, 0) as col", 1, 2, 3)
func (b SelectBuilder) Column(column interface{}, args ...interface{}) SelectBuilder {
return builder.Append(b, "Columns", newPart(column, args...)).(SelectBuilder)
}
Expand Down

0 comments on commit 2cfc5b8

Please sign in to comment.