diff --git a/lib/sqlbuilder/builder.go b/lib/sqlbuilder/builder.go
index f7e7ba90d8b28763b4bcef031616a1efe839053a..2f953fc53e243285683d9a2f232ffa998ca038cb 100644
--- a/lib/sqlbuilder/builder.go
+++ b/lib/sqlbuilder/builder.go
@@ -173,11 +173,10 @@ func (b *sqlBuilder) InsertInto(table string) Inserter {
 func (b *sqlBuilder) DeleteFrom(table string) Deleter {
 	qd := &deleter{
 		builder: b,
-		table:   table,
 	}
 
 	qd.stringer = &stringer{qd, b.t.Template}
-	return qd
+	return qd.setTable(table)
 }
 
 func (b *sqlBuilder) Update(table string) Updater {
diff --git a/lib/sqlbuilder/delete.go b/lib/sqlbuilder/delete.go
index 779262e28c24e0135e84333d14e951c5ed4c7957..8f24f5feaf80e892a393d57e0b97db713b03ec89 100644
--- a/lib/sqlbuilder/delete.go
+++ b/lib/sqlbuilder/delete.go
@@ -2,52 +2,147 @@ package sqlbuilder
 
 import (
 	"database/sql"
+	"strings"
 
 	"upper.io/db.v2/internal/sqladapter/exql"
 )
 
-type deleter struct {
-	*stringer
-	builder   *sqlBuilder
+type deleterQuery struct {
 	table     string
 	limit     int
 	where     *exql.Where
 	arguments []interface{}
 }
 
-func (qd *deleter) Where(terms ...interface{}) Deleter {
-	where, arguments := toWhereWithArguments(terms)
-	qd.where = &where
-	qd.arguments = append(qd.arguments, arguments...)
-	return qd
+func (dq *deleterQuery) statement() *exql.Statement {
+	stmt := &exql.Statement{
+		Type:  exql.Delete,
+		Table: exql.TableWithName(dq.table),
+	}
+
+	if dq.where != nil {
+		stmt.Where = dq.where
+	}
+
+	if dq.limit != 0 {
+		stmt.Limit = exql.Limit(dq.limit)
+	}
+
+	return stmt
 }
 
-func (qd *deleter) Limit(limit int) Deleter {
-	qd.limit = limit
-	return qd
+type deleter struct {
+	*stringer
+	builder *sqlBuilder
+
+	fn   func(*deleterQuery) error
+	prev *deleter
 }
 
-func (qd *deleter) Arguments() []interface{} {
-	return qd.arguments
+func (del *deleter) Builder() *sqlBuilder {
+	p := &del
+	for {
+		if (*p).builder != nil {
+			return (*p).builder
+		}
+		if (*p).prev == nil {
+			return nil
+		}
+		p = &(*p).prev
+	}
 }
 
-func (qd *deleter) Exec() (sql.Result, error) {
-	return qd.builder.sess.StatementExec(qd.statement(), qd.arguments...)
+func (del *deleter) Stringer() *stringer {
+	p := &del
+	for {
+		if (*p).stringer != nil {
+			return (*p).stringer
+		}
+		if (*p).prev == nil {
+			return nil
+		}
+		p = &(*p).prev
+	}
 }
 
-func (qd *deleter) statement() *exql.Statement {
-	stmt := &exql.Statement{
-		Type:  exql.Delete,
-		Table: exql.TableWithName(qd.table),
+func (del *deleter) String() string {
+	query, err := del.build()
+	if err != nil {
+		return ""
 	}
+	q := del.Stringer().compileAndReplacePlaceholders(query.statement())
+	q = reInvisibleChars.ReplaceAllString(q, ` `)
+	return strings.TrimSpace(q)
+}
 
-	if qd.Where != nil {
-		stmt.Where = qd.where
+func (del *deleter) setTable(table string) *deleter {
+	return del.frame(func(uq *deleterQuery) error {
+		uq.table = table
+		return nil
+	})
+}
+
+func (del *deleter) frame(fn func(*deleterQuery) error) *deleter {
+	return &deleter{prev: del, fn: fn}
+}
+
+func (del *deleter) Where(terms ...interface{}) Deleter {
+	return del.frame(func(dq *deleterQuery) error {
+		where, arguments := toWhereWithArguments(terms)
+		dq.where = &where
+		dq.arguments = append(dq.arguments, arguments...)
+		return nil
+	})
+}
+
+func (del *deleter) Limit(limit int) Deleter {
+	return del.frame(func(dq *deleterQuery) error {
+		dq.limit = limit
+		return nil
+	})
+}
+
+func (del *deleter) Arguments() []interface{} {
+	dq, err := del.build()
+	if err != nil {
+		return nil
 	}
+	return dq.arguments
+}
 
-	if qd.limit != 0 {
-		stmt.Limit = exql.Limit(qd.limit)
+func (del *deleter) Exec() (sql.Result, error) {
+	dq, err := del.build()
+	if err != nil {
+		return nil, err
 	}
+	return del.builder.sess.StatementExec(dq.statement(), dq.arguments...)
+}
 
-	return stmt
+func (del *deleter) statement() *exql.Statement {
+	iq, _ := del.build()
+	return iq.statement()
+}
+
+func (del *deleter) build() (*deleterQuery, error) {
+	iq, err := deleterFastForward(&deleterQuery{}, del)
+	if err != nil {
+		return nil, err
+	}
+	return iq, nil
+}
+
+func (del *deleter) Compile() string {
+	return del.statement().Compile(del.Stringer().t)
+}
+
+func deleterFastForward(in *deleterQuery, curr *deleter) (*deleterQuery, error) {
+	if curr == nil || curr.fn == nil {
+		return in, nil
+	}
+	in, err := deleterFastForward(in, curr.prev)
+	if err != nil {
+		return nil, err
+	}
+	err = curr.fn(in)
+	return in, err
 }