diff --git a/builder/insert.go b/builder/insert.go index 3ab646d..71dcf11 100644 --- a/builder/insert.go +++ b/builder/insert.go @@ -50,7 +50,7 @@ func (b Insert) Values(values ...interface{}) Insert { panic("loukoum: insert builder has values clause already defined") } - b.query.Values = stmt.NewValues(stmt.NewArrayExpression(values...)) + b.query.Values = stmt.NewValues(stmt.NewArrayListExpression(values...)) return b } @@ -116,7 +116,7 @@ func (b Insert) Set(args ...interface{}) Insert { pairs := ToSet(args).Pairs columns, expressions := pairs.Values() - array := stmt.NewArrayExpression(expressions) + array := stmt.NewArrayListExpression(expressions) values := stmt.NewValues(array) b.query.Columns = columns diff --git a/builder/insert_test.go b/builder/insert_test.go index cebe730..b2d6041 100644 --- a/builder/insert_test.go +++ b/builder/insert_test.go @@ -99,6 +99,17 @@ func TestInsert_Values(t *testing.T) { NamedQuery: "INSERT INTO \"table\" (\"data\") VALUES (:arg_1)", Args: []interface{}{[]byte{1, 2, 3}}, }, + { + Name: "With multiple values", + Builders: []builder.Builder{ + loukoum.Insert("table").Values([][]string{{"va", "vb", "vc"}, {"wa", "wb", "wc"}}), + loukoum.Insert("table").Values([][]interface{}{{"va", "vb", "vc"}, {"wa", "wb", "wc"}}), + }, + String: "INSERT INTO \"table\" VALUES ('va', 'vb', 'vc'), ('wa', 'wb', 'wc')", + Query: "INSERT INTO \"table\" VALUES ($1, $2, $3), ($4, $5, $6)", + NamedQuery: "INSERT INTO \"table\" VALUES (:arg_1, :arg_2, :arg_3), (:arg_4, :arg_5, :arg_6)", + Args: []interface{}{"va", "vb", "vc", "wa", "wb", "wc"}, + }, }) } diff --git a/stmt/expression.go b/stmt/expression.go index 2261204..bc9d052 100644 --- a/stmt/expression.go +++ b/stmt/expression.go @@ -281,6 +281,97 @@ var _ Expression = Value{} // Array // ---------------------------------------------------------------------------- +// ArrayList contains a list of array expression values. +type ArrayList struct { + Values []Expression +} + +// NewArrayListExpression creates a new Expression using a list of values. +func NewArrayListExpression(values ...interface{}) Expression { // nolint: gocyclo + // We pass only one argument and it's a slice or an expression. + arraylist := toArrayList(values[0]) + if len(arraylist.Values) == 0 { + arraylist.Values = []Expression{NewArrayExpression(values...)} + + } + return arraylist +} + +func toArrayList(value interface{}) ArrayList { // nolint: gocyclo + arraylist := ArrayList{} + switch values := value.(type) { + case [][]interface{}: + for i := range values { + arraylist.Values = append(arraylist.Values, NewArrayExpression(values[i]...)) + } + case [][]string: + for i := range values { + raws := make([]interface{}, len(values[i])) + for j := range values[i] { + raws[j] = values[i][j] + } + + arraylist.Values = append(arraylist.Values, NewArrayExpression(raws...)) + } + case [][]int: + for i := range values { + raws := make([]interface{}, len(values[i])) + for j := range values[i] { + raws[j] = values[i][j] + } + arraylist.Values = append(arraylist.Values, NewArrayExpression(raws...)) + } + case [][]int64: + for i := range values { + raws := make([]interface{}, len(values[i])) + for j := range values[i] { + raws[j] = values[i][j] + } + arraylist.Values = append(arraylist.Values, NewArrayExpression(raws...)) + } + case [][]bool: + for i := range values { + raws := make([]interface{}, len(values[i])) + for j := range values[i] { + raws[j] = values[i][j] + } + arraylist.Values = append(arraylist.Values, NewArrayExpression(raws...)) + } + case [][]Expression: + for i := range values { + raws := make([]interface{}, len(values[i])) + for j := range values[i] { + raws[j] = values[i][j] + } + arraylist.Values = append(arraylist.Values, NewArrayExpression(raws...)) + } + } + + return arraylist +} + +func (ArrayList) expression() {} + +// Write exposes statement as a SQL query. +func (array ArrayList) Write(ctx types.Context) { + for i, value := range array.Values { + if i > 0 { + ctx.Write(", ") + } + ctx.Write("(") + value.Write(ctx) + ctx.Write(")") + } +} + +// IsEmpty returns true if statement is undefined. +func (array ArrayList) IsEmpty() bool { + return len(array.Values) == 0 +} + +// Ensure that Array is an Expression +var _ Expression = ArrayList{} + // Array contains a list of expression values. type Array struct { Values []Expression diff --git a/stmt/values.go b/stmt/values.go index 65d4c1e..49a7a1e 100644 --- a/stmt/values.go +++ b/stmt/values.go @@ -24,9 +24,8 @@ func (values Values) Write(ctx types.Context) { } ctx.Write(token.Values.String()) - ctx.Write(" (") + ctx.Write(" ") values.Values.Write(ctx) - ctx.Write(")") } // IsEmpty returns true if statement is undefined.