package squirrel
import (
"bytes"
"database/sql"
"errors"
"fmt"
"io"
"sort"
"strings"
"github.com/lann/builder"
)
type insertData struct {
PlaceholderFormat PlaceholderFormat
RunWith BaseRunner
Prefixes []Sqlizer
StatementKeyword string
Options []string
Into string
Columns []string
Values [][]interface {}
Suffixes []Sqlizer
Select *SelectBuilder
}
func (d *insertData ) Exec () (sql .Result , error ) {
if d .RunWith == nil {
return nil , RunnerNotSet
}
return ExecWith (d .RunWith , d )
}
func (d *insertData ) Query () (*sql .Rows , error ) {
if d .RunWith == nil {
return nil , RunnerNotSet
}
return QueryWith (d .RunWith , d )
}
func (d *insertData ) QueryRow () RowScanner {
if d .RunWith == nil {
return &Row {err : RunnerNotSet }
}
queryRower , ok := d .RunWith .(QueryRower )
if !ok {
return &Row {err : RunnerNotQueryRunner }
}
return QueryRowWith (queryRower , d )
}
func (d *insertData ) ToSql () (sqlStr string , args []interface {}, err error ) {
if len (d .Into ) == 0 {
err = errors .New ("insert statements must specify a table" )
return
}
if len (d .Values ) == 0 && d .Select == nil {
err = errors .New ("insert statements must have at least one set of values or select clause" )
return
}
sql := &bytes .Buffer {}
if len (d .Prefixes ) > 0 {
args , err = appendToSql (d .Prefixes , sql , " " , args )
if err != nil {
return
}
sql .WriteString (" " )
}
if d .StatementKeyword == "" {
sql .WriteString ("INSERT " )
} else {
sql .WriteString (d .StatementKeyword )
sql .WriteString (" " )
}
if len (d .Options ) > 0 {
sql .WriteString (strings .Join (d .Options , " " ))
sql .WriteString (" " )
}
sql .WriteString ("INTO " )
sql .WriteString (d .Into )
sql .WriteString (" " )
if len (d .Columns ) > 0 {
sql .WriteString ("(" )
sql .WriteString (strings .Join (d .Columns , "," ))
sql .WriteString (") " )
}
if d .Select != nil {
args , err = d .appendSelectToSQL (sql , args )
} else {
args , err = d .appendValuesToSQL (sql , args )
}
if err != nil {
return
}
if len (d .Suffixes ) > 0 {
sql .WriteString (" " )
args , err = appendToSql (d .Suffixes , sql , " " , args )
if err != nil {
return
}
}
sqlStr , err = d .PlaceholderFormat .ReplacePlaceholders (sql .String ())
return
}
func (d *insertData ) appendValuesToSQL (w io .Writer , args []interface {}) ([]interface {}, error ) {
if len (d .Values ) == 0 {
return args , errors .New ("values for insert statements are not set" )
}
io .WriteString (w , "VALUES " )
valuesStrings := make ([]string , len (d .Values ))
for r , row := range d .Values {
valueStrings := make ([]string , len (row ))
for v , val := range row {
if vs , ok := val .(Sqlizer ); ok {
vsql , vargs , err := vs .ToSql ()
if err != nil {
return nil , err
}
valueStrings [v ] = vsql
args = append (args , vargs ...)
} else {
valueStrings [v ] = "?"
args = append (args , val )
}
}
valuesStrings [r ] = fmt .Sprintf ("(%s)" , strings .Join (valueStrings , "," ))
}
io .WriteString (w , strings .Join (valuesStrings , "," ))
return args , nil
}
func (d *insertData ) appendSelectToSQL (w io .Writer , args []interface {}) ([]interface {}, error ) {
if d .Select == nil {
return args , errors .New ("select clause for insert statements are not set" )
}
selectClause , sArgs , err := d .Select .ToSql ()
if err != nil {
return args , err
}
io .WriteString (w , selectClause )
args = append (args , sArgs ...)
return args , nil
}