Skip to content

Commit

Permalink
Merge pull request #116 from huandu/feature-generate-sql-only-when-va…
Browse files Browse the repository at this point in the history
…lue-is-set

Fix #115: Generate SQL only when necessary values are set
  • Loading branch information
huandu committed Jul 22, 2023
2 parents 20d1fd8 + a7c8a3c commit 15280ec
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 108 deletions.
10 changes: 5 additions & 5 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (args *Args) Compile(format string, initialValue ...interface{}) (query str
//
// See doc for `Compile` to learn details.
func (args *Args) CompileWithFlavor(format string, flavor Flavor, initialValue ...interface{}) (query string, values []interface{}) {
buf := &strings.Builder{}
buf := newStringBuilder()
idx := strings.IndexRune(format, '$')
offset := 0
values = initialValue
Expand Down Expand Up @@ -160,7 +160,7 @@ func (args *Args) CompileWithFlavor(format string, flavor Flavor, initialValue .
return
}

func (args *Args) compileNamed(buf *strings.Builder, flavor Flavor, format string, values []interface{}) (string, []interface{}) {
func (args *Args) compileNamed(buf *stringBuilder, flavor Flavor, format string, values []interface{}) (string, []interface{}) {
i := 1

for ; i < len(format) && format[i] != '}'; i++ {
Expand All @@ -182,7 +182,7 @@ func (args *Args) compileNamed(buf *strings.Builder, flavor Flavor, format strin
return format, values
}

func (args *Args) compileDigits(buf *strings.Builder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
func (args *Args) compileDigits(buf *stringBuilder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
i := 1

for ; i < len(format) && '0' <= format[i] && format[i] <= '9'; i++ {
Expand All @@ -199,7 +199,7 @@ func (args *Args) compileDigits(buf *strings.Builder, flavor Flavor, format stri
return format, values, offset
}

func (args *Args) compileSuccessive(buf *strings.Builder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
func (args *Args) compileSuccessive(buf *stringBuilder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
if offset >= len(args.args) {
return format, values, offset
}
Expand All @@ -210,7 +210,7 @@ func (args *Args) compileSuccessive(buf *strings.Builder, flavor Flavor, format
return format, values, offset + 1
}

func (args *Args) compileArg(buf *strings.Builder, flavor Flavor, values []interface{}, arg interface{}) []interface{} {
func (args *Args) compileArg(buf *stringBuilder, flavor Flavor, values []interface{}, arg interface{}) []interface{} {
switch a := arg.(type) {
case Builder:
var s string
Expand Down
42 changes: 21 additions & 21 deletions cond.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Cond struct {

// Equal represents "field = value".
func (c *Cond) Equal(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" = ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -28,7 +28,7 @@ func (c *Cond) E(field string, value interface{}) string {

// NotEqual represents "field <> value".
func (c *Cond) NotEqual(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" <> ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -42,7 +42,7 @@ func (c *Cond) NE(field string, value interface{}) string {

// GreaterThan represents "field > value".
func (c *Cond) GreaterThan(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" > ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -56,7 +56,7 @@ func (c *Cond) G(field string, value interface{}) string {

// GreaterEqualThan represents "field >= value".
func (c *Cond) GreaterEqualThan(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" >= ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -70,7 +70,7 @@ func (c *Cond) GE(field string, value interface{}) string {

// LessThan represents "field < value".
func (c *Cond) LessThan(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" < ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -84,7 +84,7 @@ func (c *Cond) L(field string, value interface{}) string {

// LessEqualThan represents "field <= value".
func (c *Cond) LessEqualThan(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" <= ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -104,7 +104,7 @@ func (c *Cond) In(field string, value ...interface{}) string {
vs = append(vs, c.Args.Add(v))
}

buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" IN (")
buf.WriteString(strings.Join(vs, ", "))
Expand All @@ -120,7 +120,7 @@ func (c *Cond) NotIn(field string, value ...interface{}) string {
vs = append(vs, c.Args.Add(v))
}

buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" NOT IN (")
buf.WriteString(strings.Join(vs, ", "))
Expand All @@ -130,7 +130,7 @@ func (c *Cond) NotIn(field string, value ...interface{}) string {

// Like represents "field LIKE value".
func (c *Cond) Like(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" LIKE ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -139,7 +139,7 @@ func (c *Cond) Like(field string, value interface{}) string {

// NotLike represents "field NOT LIKE value".
func (c *Cond) NotLike(field string, value interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" NOT LIKE ")
buf.WriteString(c.Args.Add(value))
Expand All @@ -148,23 +148,23 @@ func (c *Cond) NotLike(field string, value interface{}) string {

// IsNull represents "field IS NULL".
func (c *Cond) IsNull(field string) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" IS NULL")
return buf.String()
}

// IsNotNull represents "field IS NOT NULL".
func (c *Cond) IsNotNull(field string) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" IS NOT NULL")
return buf.String()
}

// Between represents "field BETWEEN lower AND upper".
func (c *Cond) Between(field string, lower, upper interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" BETWEEN ")
buf.WriteString(c.Args.Add(lower))
Expand All @@ -175,7 +175,7 @@ func (c *Cond) Between(field string, lower, upper interface{}) string {

// NotBetween represents "field NOT BETWEEN lower AND upper".
func (c *Cond) NotBetween(field string, lower, upper interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" NOT BETWEEN ")
buf.WriteString(c.Args.Add(lower))
Expand All @@ -186,7 +186,7 @@ func (c *Cond) NotBetween(field string, lower, upper interface{}) string {

// Or represents OR logic like "expr1 OR expr2 OR expr3".
func (c *Cond) Or(orExpr ...string) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString("(")
buf.WriteString(strings.Join(orExpr, " OR "))
buf.WriteString(")")
Expand All @@ -195,7 +195,7 @@ func (c *Cond) Or(orExpr ...string) string {

// And represents AND logic like "expr1 AND expr2 AND expr3".
func (c *Cond) And(andExpr ...string) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString("(")
buf.WriteString(strings.Join(andExpr, " AND "))
buf.WriteString(")")
Expand All @@ -204,7 +204,7 @@ func (c *Cond) And(andExpr ...string) string {

// Exists represents "EXISTS (subquery)".
func (c *Cond) Exists(subquery interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString("EXISTS (")
buf.WriteString(c.Args.Add(subquery))
buf.WriteString(")")
Expand All @@ -213,7 +213,7 @@ func (c *Cond) Exists(subquery interface{}) string {

// NotExists represents "NOT EXISTS (subquery)".
func (c *Cond) NotExists(subquery interface{}) string {
buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString("NOT EXISTS (")
buf.WriteString(c.Args.Add(subquery))
buf.WriteString(")")
Expand All @@ -228,7 +228,7 @@ func (c *Cond) Any(field, op string, value ...interface{}) string {
vs = append(vs, c.Args.Add(v))
}

buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" ")
buf.WriteString(op)
Expand All @@ -246,7 +246,7 @@ func (c *Cond) All(field, op string, value ...interface{}) string {
vs = append(vs, c.Args.Add(v))
}

buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" ")
buf.WriteString(op)
Expand All @@ -264,7 +264,7 @@ func (c *Cond) Some(field, op string, value ...interface{}) string {
vs = append(vs, c.Args.Add(v))
}

buf := &strings.Builder{}
buf := newStringBuilder()
buf.WriteString(Escape(field))
buf.WriteString(" ")
buf.WriteString(op)
Expand Down
21 changes: 12 additions & 9 deletions createtable.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,25 @@ func (ctb *CreateTableBuilder) Build() (sql string, args []interface{}) {
// BuildWithFlavor returns compiled CREATE TABLE string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (ctb *CreateTableBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &strings.Builder{}
buf := newStringBuilder()
ctb.injection.WriteTo(buf, createTableMarkerInit)
buf.WriteString(ctb.verb)

if len(ctb.verb) > 0 {
buf.WriteLeadingString(ctb.verb)
}

if ctb.ifNotExists {
buf.WriteString(" IF NOT EXISTS")
buf.WriteLeadingString("IF NOT EXISTS")
}

if len(ctb.table) > 0 {
buf.WriteLeadingString(ctb.table)
}

buf.WriteRune(' ')
buf.WriteString(ctb.table)
ctb.injection.WriteTo(buf, createTableMarkerAfterCreate)

if len(ctb.defs) > 0 {
buf.WriteString(" (")
buf.WriteLeadingString("(")

defs := make([]string, 0, len(ctb.defs))

Expand All @@ -128,15 +133,13 @@ func (ctb *CreateTableBuilder) BuildWithFlavor(flavor Flavor, initialArg ...inte
}

if len(ctb.options) > 0 {
buf.WriteRune(' ')

opts := make([]string, 0, len(ctb.options))

for _, opt := range ctb.options {
opts = append(opts, strings.Join(opt, " "))
}

buf.WriteString(strings.Join(opts, ", "))
buf.WriteLeadingString(strings.Join(opts, ", "))
ctb.injection.WriteTo(buf, createTableMarkerAfterOption)
}

Expand Down
16 changes: 10 additions & 6 deletions delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,25 @@ func (db *DeleteBuilder) Build() (sql string, args []interface{}) {
// BuildWithFlavor returns compiled DELETE string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &strings.Builder{}
buf := newStringBuilder()
db.injection.WriteTo(buf, deleteMarkerInit)
buf.WriteString("DELETE FROM ")
buf.WriteString(db.table)

if len(db.table) > 0 {
buf.WriteLeadingString("DELETE FROM ")
buf.WriteString(db.table)
}

db.injection.WriteTo(buf, deleteMarkerAfterDeleteFrom)

if len(db.whereExprs) > 0 {
buf.WriteString(" WHERE ")
buf.WriteLeadingString("WHERE ")
buf.WriteString(strings.Join(db.whereExprs, " AND "))

db.injection.WriteTo(buf, deleteMarkerAfterWhere)
}

if len(db.orderByCols) > 0 {
buf.WriteString(" ORDER BY ")
buf.WriteLeadingString("ORDER BY ")
buf.WriteString(strings.Join(db.orderByCols, ", "))

if db.order != "" {
Expand All @@ -139,7 +143,7 @@ func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
}

if db.limit >= 0 {
buf.WriteString(" LIMIT ")
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(db.limit))

db.injection.WriteTo(buf, deleteMarkerAfterLimit)
Expand Down
13 changes: 2 additions & 11 deletions injection.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,13 @@ func (injection *injection) SQL(marker injectionMarker, sql string) {

// WriteTo joins all SQL strings at the same marker value with blank (" ")
// and writes the joined value to buf.
func (injection *injection) WriteTo(buf *strings.Builder, marker injectionMarker) {
func (injection *injection) WriteTo(buf *stringBuilder, marker injectionMarker) {
sqls := injection.markerSQLs[marker]
notEmpty := buf.Len() > 0

if len(sqls) == 0 {
return
}

if notEmpty {
buf.WriteRune(' ')
}

s := strings.Join(sqls, " ")
buf.WriteString(s)

if !notEmpty {
buf.WriteRune(' ')
}
buf.WriteLeadingString(s)
}
27 changes: 17 additions & 10 deletions insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,29 +117,36 @@ func (ib *InsertBuilder) Build() (sql string, args []interface{}) {
// BuildWithFlavor returns compiled INSERT string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &strings.Builder{}
buf := newStringBuilder()
ib.injection.WriteTo(buf, insertMarkerInit)
buf.WriteString(ib.verb)
buf.WriteString(" INTO ")
buf.WriteString(ib.table)

if len(ib.table) > 0 {
buf.WriteLeadingString(ib.verb)
buf.WriteString(" INTO ")
buf.WriteString(ib.table)
}

ib.injection.WriteTo(buf, insertMarkerAfterInsertInto)

if len(ib.cols) > 0 {
buf.WriteString(" (")
buf.WriteLeadingString("(")
buf.WriteString(strings.Join(ib.cols, ", "))
buf.WriteString(")")

ib.injection.WriteTo(buf, insertMarkerAfterCols)
}

buf.WriteString(" VALUES ")
values := make([]string, 0, len(ib.values))
if len(ib.values) > 0 {
buf.WriteLeadingString("VALUES ")
values := make([]string, 0, len(ib.values))

for _, v := range ib.values {
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
}

for _, v := range ib.values {
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
buf.WriteString(strings.Join(values, ", "))
}

buf.WriteString(strings.Join(values, ", "))
ib.injection.WriteTo(buf, insertMarkerAfterValues)

return ib.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
Expand Down
Loading

0 comments on commit 15280ec

Please sign in to comment.