grouped sql statment generation into a file, moved tests from sqlExportWriter to sql pkg

This commit is contained in:
Andy Arthur
2019-12-04 14:36:03 -08:00
parent 85225b9961
commit e29e9cf900
9 changed files with 456 additions and 444 deletions
-64
View File
@@ -16,69 +16,10 @@ package sql
import (
"fmt"
"strings"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
dtypes "github.com/liquidata-inc/dolt/go/libraries/doltcore/sqle/types"
)
// SchemaAsCreateStmt takes a Schema and returns a string representing a SQL create table command that could be used to
// create this table
func SchemaAsCreateStmt(tableName string, sch schema.Schema) string {
sb := &strings.Builder{}
fmt.Fprintf(sb, "CREATE TABLE %s (\n", QuoteIdentifier(tableName))
firstLine := true
sch.GetAllCols().IterInSortedOrder(func(tag uint64, col schema.Column) (stop bool) {
if firstLine {
firstLine = false
} else {
sb.WriteString(",\n")
}
s := FmtCol(2, 0, 0, col)
sb.WriteString(s)
return false
})
firstPK := true
err := sch.GetPKCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
if firstPK {
sb.WriteString(",\n PRIMARY KEY (")
firstPK = false
} else {
sb.WriteRune(',')
}
sb.WriteString(QuoteIdentifier(col.Name))
return false, nil
})
// TODO: fix panics
if err != nil {
panic(err)
}
sb.WriteString(")\n);")
return sb.String()
}
func TableDropStmt(tableName string) string {
var b strings.Builder
b.WriteString("DROP TABLE ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(";")
return b.String()
}
func TableDropIfExistsStmt(tableName string) string {
var b strings.Builder
b.WriteString("DROP TABLE IF EXISTS ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(";")
return b.String()
}
// FmtCol converts a column to a string with a given indent space count, name width, and type width. If nameWidth or
// typeWidth are 0 or less than the length of the name or type, then the length of the name or type will be used
func FmtCol(indent, nameWidth, typeWidth int, col schema.Column) string {
@@ -109,11 +50,6 @@ func FmtColWithNameAndType(indent, nameWidth, typeWidth int, colName, typeStr st
return colStr + fmt.Sprintf(" COMMENT 'tag:%d'", col.Tag)
}
// Quotes the identifier given with backticks.
func QuoteIdentifier(s string) string {
return "`" + s + "`"
}
// FmtColPrimaryKey creates a string representing a primary key constraint within a sql create table statement with a
// given indent.
func FmtColPrimaryKey(indent int, colStr string) string {
-20
View File
@@ -16,7 +16,6 @@ package sql
import (
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/sql/sqltestutil"
"github.com/liquidata-inc/dolt/go/store/types"
"testing"
@@ -24,25 +23,6 @@ import (
"github.com/stretchr/testify/assert"
)
const expectedSQL = "CREATE TABLE `table_name` (\n" +
" `id` BIGINT NOT NULL COMMENT 'tag:0',\n" +
" `first` LONGTEXT NOT NULL COMMENT 'tag:1',\n" +
" `last` LONGTEXT NOT NULL COMMENT 'tag:2',\n" +
" `is_married` BOOLEAN COMMENT 'tag:3',\n" +
" `age` BIGINT COMMENT 'tag:4',\n" +
" `rating` DOUBLE COMMENT 'tag:6',\n" +
" `uuid` LONGTEXT COMMENT 'tag:7',\n" +
" `num_episodes` BIGINT UNSIGNED COMMENT 'tag:8',\n" +
" PRIMARY KEY (`id`)\n" +
");"
func TestSchemaAsCreateStmt(t *testing.T) {
tSchema := sqltestutil.PeopleTestSchema
str := SchemaAsCreateStmt("table_name", tSchema)
assert.Equal(t, expectedSQL, str)
}
func TestFmtCol(t *testing.T) {
tests := []struct {
Col schema.Column
-37
View File
@@ -18,11 +18,7 @@ import (
"context"
"errors"
"fmt"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
"github.com/liquidata-inc/dolt/go/store/types"
"io"
"strings"
"vitess.io/vitess/go/vt/sqlparser"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/doltdb"
@@ -143,39 +139,6 @@ func ExecuteDelete(ctx context.Context, db *doltdb.DoltDB, root *doltdb.RootValu
return &result, nil
}
func RowAsDeleteStmt(r row.Row, tableName string, tableSch schema.Schema) (string, error) {
var b strings.Builder
b.WriteString("DELETE FROM ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(" WHERE (")
seenOne := false
_, err := r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
col := tableSch.GetAllCols().TagToCol[tag]
if col.IsPartOfPK {
if seenOne {
b.WriteString(" AND ")
}
sqlString, err := ValueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(QuoteIdentifier(col.Name))
b.WriteRune('=')
b.WriteString(sqlString)
seenOne = true
}
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(");")
return b.String(), nil
}
func errDelete(errorFmt string, args ...interface{}) (*DeleteResult, error) {
return nil, errors.New(fmt.Sprintf(errorFmt, args...))
}
-47
View File
@@ -167,53 +167,6 @@ func ExecuteInsert(
}, nil
}
func RowAsInsertStmt(r row.Row, tableName string, tableSch schema.Schema) (string, error) {
var b strings.Builder
b.WriteString("INSERT INTO ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(" ")
b.WriteString("(")
seenOne := false
err := tableSch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
if seenOne {
b.WriteRune(',')
}
b.WriteString(QuoteIdentifier(col.Name))
seenOne = true
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(")")
b.WriteString(" VALUES (")
seenOne = false
_, err = r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
if seenOne {
b.WriteRune(',')
}
sqlString, err := ValueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(sqlString)
seenOne = true
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(");")
return b.String(), nil
}
// Returns a primary key summary of the row given
func getPrimaryKeyString(r row.Row, tableSch schema.Schema) string {
var sb strings.Builder
+261
View File
@@ -0,0 +1,261 @@
// Copyright 2019 Liquidata, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sql
import (
"fmt"
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
"github.com/liquidata-inc/dolt/go/store/types"
"strings"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
)
// SchemaAsCreateStmt takes a Schema and returns a string representing a SQL create table command that could be used to
// create this table
func SchemaAsCreateStmt(tableName string, sch schema.Schema) string {
sb := &strings.Builder{}
fmt.Fprintf(sb, "CREATE TABLE %s (\n", QuoteIdentifier(tableName))
firstLine := true
sch.GetAllCols().IterInSortedOrder(func(tag uint64, col schema.Column) (stop bool) {
if firstLine {
firstLine = false
} else {
sb.WriteString(",\n")
}
s := FmtCol(2, 0, 0, col)
sb.WriteString(s)
return false
})
firstPK := true
err := sch.GetPKCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
if firstPK {
sb.WriteString(",\n PRIMARY KEY (")
firstPK = false
} else {
sb.WriteRune(',')
}
sb.WriteString(QuoteIdentifier(col.Name))
return false, nil
})
// TODO: fix panics
if err != nil {
panic(err)
}
sb.WriteString(")\n);")
return sb.String()
}
func TableDropStmt(tableName string) string {
var b strings.Builder
b.WriteString("DROP TABLE ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(";")
return b.String()
}
func TableDropIfExistsStmt(tableName string) string {
var b strings.Builder
b.WriteString("DROP TABLE IF EXISTS ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(";")
return b.String()
}
func RowAsInsertStmt(r row.Row, tableName string, tableSch schema.Schema) (string, error) {
var b strings.Builder
b.WriteString("INSERT INTO ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(" ")
b.WriteString("(")
seenOne := false
err := tableSch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
if seenOne {
b.WriteRune(',')
}
b.WriteString(QuoteIdentifier(col.Name))
seenOne = true
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(")")
b.WriteString(" VALUES (")
seenOne = false
_, err = r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
if seenOne {
b.WriteRune(',')
}
sqlString, err := valueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(sqlString)
seenOne = true
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(");")
return b.String(), nil
}
func RowAsDeleteStmt(r row.Row, tableName string, tableSch schema.Schema) (string, error) {
var b strings.Builder
b.WriteString("DELETE FROM ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(" WHERE (")
seenOne := false
_, err := r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
col := tableSch.GetAllCols().TagToCol[tag]
if col.IsPartOfPK {
if seenOne {
b.WriteString(" AND ")
}
sqlString, err := valueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(QuoteIdentifier(col.Name))
b.WriteRune('=')
b.WriteString(sqlString)
seenOne = true
}
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(");")
return b.String(), nil
}
func RowAsUpdateStmt(r row.Row, tableName string, tableSch schema.Schema) (string, error) {
var b strings.Builder
b.WriteString("UPDATE ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(" ")
b.WriteString("SET ")
seenOne := false
_, err := r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
col := tableSch.GetAllCols().TagToCol[tag]
if !col.IsPartOfPK {
if seenOne {
b.WriteRune(',')
}
sqlString, err := valueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(QuoteIdentifier(col.Name))
b.WriteRune('=')
b.WriteString(sqlString)
seenOne = true
}
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(" WHERE (")
seenOne = false
_, err = r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
col := tableSch.GetAllCols().TagToCol[tag]
if col.IsPartOfPK {
if seenOne {
b.WriteString(" AND ")
}
sqlString, err := valueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(QuoteIdentifier(col.Name))
b.WriteRune('=')
b.WriteString(sqlString)
seenOne = true
}
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(");")
return b.String(), nil
}
// Quotes the identifier given with backticks.
func QuoteIdentifier(s string) string {
return "`" + s + "`"
}
func valueAsSqlString(value types.Value) (string, error) {
if types.IsNull(value) {
return "NULL", nil
}
switch value.Kind() {
case types.BoolKind:
if value.(types.Bool) {
return "TRUE", nil
} else {
return "FALSE", nil
}
case types.UUIDKind:
convFn, err := doltcore.GetConvFunc(value.Kind(), types.StringKind)
if err != nil {
return "", err
}
str, _ := convFn(value)
return doubleQuot + string(str.(types.String)) + doubleQuot, nil
case types.StringKind:
s := string(value.(types.String))
s = strings.ReplaceAll(s, doubleQuot, "\\\"")
return doubleQuot + s + doubleQuot, nil
default:
convFn, err := doltcore.GetConvFunc(value.Kind(), types.StringKind)
if err != nil {
return "", err
}
str, err := convFn(value)
if err != nil {
return "", err
}
return string(str.(types.String)), nil
}
}
@@ -0,0 +1,193 @@
// Copyright 2019 Liquidata, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sql
import (
"testing"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/dtestutils"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/sql/sqltestutil"
"github.com/liquidata-inc/dolt/go/store/types"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)
const expectedCreateSQL = "CREATE TABLE `table_name` (\n" +
" `id` BIGINT NOT NULL COMMENT 'tag:0',\n" +
" `first` LONGTEXT NOT NULL COMMENT 'tag:1',\n" +
" `last` LONGTEXT NOT NULL COMMENT 'tag:2',\n" +
" `is_married` BOOLEAN COMMENT 'tag:3',\n" +
" `age` BIGINT COMMENT 'tag:4',\n" +
" `rating` DOUBLE COMMENT 'tag:6',\n" +
" `uuid` LONGTEXT COMMENT 'tag:7',\n" +
" `num_episodes` BIGINT UNSIGNED COMMENT 'tag:8',\n" +
" PRIMARY KEY (`id`)\n" +
");"
const expectedDropSql = "DROP TABLE `table_name`;"
const expectedDropIfExistsSql = "DROP TABLE IF EXISTS `table_name`;"
type test struct {
name string
row row.Row
sch schema.Schema
expectedOutput string
}
func TestSchemaAsCreateStmt(t *testing.T) {
tSchema := sqltestutil.PeopleTestSchema
str := SchemaAsCreateStmt("table_name", tSchema)
assert.Equal(t, expectedCreateSQL, str)
}
func TestTableDropStmt(t *testing.T) {
str := TableDropStmt("table_name")
assert.Equal(t, expectedDropSql, str)
}
func TestTableDropIfExistsStmt(t *testing.T) {
str := TableDropIfExistsStmt("table_name")
assert.Equal(t, expectedDropIfExistsSql, str)
}
func TestRowAsInsertStmt(t *testing.T) {
id := uuid.MustParse("00000000-0000-0000-0000-000000000000")
tableName := "people"
tests := []test{
{
name: "simple row",
row: dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie")),
sch: dtestutils.TypedSchema,
expectedOutput: "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","some guy",100,FALSE,"normie");`,
},
{
name: "embedded quotes",
row: dtestutils.NewTypedRow(id, `It's "Mister Perfect" to you`, 100, false, strPointer("normie")),
sch: dtestutils.TypedSchema,
expectedOutput: "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","It's \"Mister Perfect\" to you",100,FALSE,"normie");`,
},
{
name: "null values",
row: dtestutils.NewTypedRow(id, "some guy", 100, false, nil),
sch: dtestutils.TypedSchema,
expectedOutput: "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","some guy",100,FALSE,NULL);`,
},
}
trickySch := dtestutils.CreateSchema(
schema.NewColumn("a name with spaces", 0, types.FloatKind, false),
schema.NewColumn("anotherColumn", 1, types.IntKind, true),
)
tests = append(tests, test{
name: "negative values and columns with spaces",
row: dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42)),
sch: trickySch,
expectedOutput: "INSERT INTO `people` (`a name with spaces`,`anotherColumn`) VALUES (-3.14,-42);",
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
stmt, err := RowAsInsertStmt(tt.row, tableName, tt.sch)
assert.NoError(t, err)
assert.Equal(t, tt.expectedOutput, stmt)
})
}
}
func TestRowAsDeleteStmt(t *testing.T) {
tableName := "tricky"
trickySch := dtestutils.CreateSchema(
schema.NewColumn("anotherCol", 0, types.FloatKind, false),
schema.NewColumn("a name with spaces", 1, types.IntKind, true),
)
tests := []test{
{
name: "negative values and columns with spaces",
row: dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42)),
sch: trickySch,
expectedOutput: "DELETE FROM `tricky` WHERE (`a name with spaces`=-42);",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
stmt, err := RowAsDeleteStmt(tt.row, tableName, tt.sch)
assert.NoError(t, err)
assert.Equal(t, tt.expectedOutput, stmt)
})
}
}
func TestRowAsUpdateStmt(t *testing.T) {
id := uuid.MustParse("00000000-0000-0000-0000-000000000000")
tableName := "people"
tests := []test{
{
name: "simple row",
row: dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie")),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"some guy\",`age`=100,`is_married`=FALSE,`title`=\"normie\" WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");",
},
{
name: "embedded quotes",
row: dtestutils.NewTypedRow(id, `It's "Mister Perfect" to you`, 100, false, strPointer("normie")),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"It's \\\"Mister Perfect\\\" to you\",`age`=100,`is_married`=FALSE,`title`=\"normie\" WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");",
},
{
name: "null values",
row: dtestutils.NewTypedRow(id, "some guy", 100, false, nil),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"some guy\",`age`=100,`is_married`=FALSE,`title`=NULL WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");",
},
}
trickySch := dtestutils.CreateSchema(
schema.NewColumn("a name with spaces", 0, types.FloatKind, false),
schema.NewColumn("anotherColumn", 1, types.IntKind, true),
)
tests = append(tests, test{
name: "negative values and columns with spaces",
row: dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42)),
sch: trickySch,
expectedOutput: "UPDATE `people` SET `a name with spaces`=-3.14 WHERE (`anotherColumn`=-42);",
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
stmt, err := RowAsUpdateStmt(tt.row, tableName, tt.sch)
assert.NoError(t, err)
assert.Equal(t, tt.expectedOutput, stmt)
})
}
}
func strPointer(s string) *string {
return &s
}
-61
View File
@@ -18,10 +18,7 @@ import (
"context"
"errors"
"fmt"
"github.com/liquidata-inc/dolt/go/store/types"
"io"
"strings"
"vitess.io/vitess/go/vt/sqlparser"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/doltdb"
@@ -224,64 +221,6 @@ func ExecuteUpdate(ctx context.Context, db *doltdb.DoltDB, root *doltdb.RootValu
return &result, nil
}
func RowAsUpdateStmt(r row.Row, tableName string, tableSch schema.Schema) (string, error) {
var b strings.Builder
b.WriteString("UPDATE ")
b.WriteString(QuoteIdentifier(tableName))
b.WriteString(" ")
b.WriteString("SET ")
seenOne := false
_, err := r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
col := tableSch.GetAllCols().TagToCol[tag]
if !col.IsPartOfPK {
if seenOne {
b.WriteRune(',')
}
sqlString, err := ValueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(QuoteIdentifier(col.Name))
b.WriteRune('=')
b.WriteString(sqlString)
seenOne = true
}
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(" WHERE (")
seenOne = false
_, err = r.IterSchema(tableSch, func(tag uint64, val types.Value) (stop bool, err error) {
col := tableSch.GetAllCols().TagToCol[tag]
if col.IsPartOfPK {
if seenOne {
b.WriteString(" AND ")
}
sqlString, err := ValueAsSqlString(val)
if err != nil {
return true, err
}
b.WriteString(QuoteIdentifier(col.Name))
b.WriteRune('=')
b.WriteString(sqlString)
seenOne = true
}
return false, nil
})
if err != nil {
return "", err
}
b.WriteString(");")
return b.String(), nil
}
func errUpdate(errorFmt string, args ...interface{}) (*UpdateResult, error) {
return nil, errors.New(fmt.Sprintf(errorFmt, args...))
}
+1 -40
View File
@@ -16,11 +16,8 @@ package sql
import (
"context"
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
"strconv"
"strings"
"github.com/google/uuid"
"strconv"
"vitess.io/vitess/go/vt/sqlparser"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
@@ -147,42 +144,6 @@ func LiteralValueGetter(value types.Value) *RowValGetter {
}
}
func ValueAsSqlString(value types.Value) (string, error) {
if types.IsNull(value) {
return "NULL", nil
}
switch value.Kind() {
case types.BoolKind:
if value.(types.Bool) {
return "TRUE", nil
} else {
return "FALSE", nil
}
case types.UUIDKind:
convFn, err := doltcore.GetConvFunc(value.Kind(), types.StringKind)
if err != nil {
return "", err
}
str, _ := convFn(value)
return doubleQuot + string(str.(types.String)) + doubleQuot, nil
case types.StringKind:
s := string(value.(types.String))
s = strings.ReplaceAll(s, doubleQuot, "\\\"")
return doubleQuot + s + doubleQuot, nil
default:
convFn, err := doltcore.GetConvFunc(value.Kind(), types.StringKind)
if err != nil {
return "", err
}
str, err := convFn(value)
if err != nil {
return "", err
}
return string(str.(types.String)), nil
}
}
// Returns a RowValGetter for the column given, or an error
func getterForColumn(qc QualifiedColumn, inputSchemas map[string]schema.Schema) (*RowValGetter, error) {
tableSch, ok := inputSchemas[qc.TableName]
@@ -26,7 +26,6 @@ import (
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
"github.com/liquidata-inc/dolt/go/libraries/doltcore/sql"
"github.com/liquidata-inc/dolt/go/store/types"
)
type StringBuilderCloser struct {
@@ -44,184 +43,11 @@ type test struct {
expectedOutput string
}
func TestWriteRow(t *testing.T) {
id := uuid.MustParse("00000000-0000-0000-0000-000000000000")
tableName := "people"
dropCreateStatement := "DROP TABLE IF EXISTS `people`;\n" + sql.SchemaAsCreateStmt(tableName, dtestutils.TypedSchema)
tests := []test{
{
name: "simple row",
rows: rs(dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie"))),
sch: dtestutils.TypedSchema,
expectedOutput: dropCreateStatement + "\n" + "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","some guy",100,FALSE,"normie");` +
"\n",
},
{
name: "embedded quotes",
rows: rs(dtestutils.NewTypedRow(id, `It's "Mister Perfect" to you`, 100, false, strPointer("normie"))),
sch: dtestutils.TypedSchema,
expectedOutput: dropCreateStatement + "\n" + "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","It's \"Mister Perfect\" to you",100,FALSE,"normie");` +
"\n",
},
{
name: "two rows",
rows: rs(
dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie")),
dtestutils.NewTypedRow(id, "guy personson", 0, true, strPointer("officially a person"))),
sch: dtestutils.TypedSchema,
expectedOutput: dropCreateStatement + "\n" +
"INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","some guy",100,FALSE,"normie");` + "\n" +
"INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","guy personson",0,TRUE,"officially a person");` + "\n",
},
{
name: "null values",
rows: rs(dtestutils.NewTypedRow(id, "some guy", 100, false, nil)),
sch: dtestutils.TypedSchema,
expectedOutput: dropCreateStatement + "\n" + "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) " +
`VALUES ("00000000-0000-0000-0000-000000000000","some guy",100,FALSE,NULL);` +
"\n",
},
}
trickySch := dtestutils.CreateSchema(
schema.NewColumn("a name with spaces", 0, types.FloatKind, false),
schema.NewColumn("anotherColumn", 1, types.IntKind, true),
)
dropCreateTricky := "DROP TABLE IF EXISTS `people`;\n" + sql.SchemaAsCreateStmt(tableName, trickySch)
tests = append(tests, test{
name: "negative values and columns with spaces",
rows: rs(dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42))),
sch: trickySch,
expectedOutput: dropCreateTricky + "\n" + "INSERT INTO `people` (`a name with spaces`,`anotherColumn`) " +
`VALUES (-3.14,-42);` +
"\n",
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var stringWr StringBuilderCloser
w := &SqlExportWriter{
tableName: tableName,
sch: tt.sch,
wr: &stringWr,
}
for _, r := range tt.rows {
assert.NoError(t, w.WriteRow(context.Background(), r))
}
assert.Equal(t, tt.expectedOutput, stringWr.String())
})
}
}
func TestDeleteRow(t *testing.T) {
tableName := "tricky"
trickySch := dtestutils.CreateSchema(
schema.NewColumn("anotherCol", 0, types.FloatKind, false),
schema.NewColumn("a name with spaces", 1, types.IntKind, true),
)
tests := []test{
{
name: "negative values and columns with spaces",
rows: rs(dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42))),
sch: trickySch,
expectedOutput: "DELETE FROM `tricky` WHERE (`a name with spaces`=-42);" + "\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var stringWr StringBuilderCloser
w := &SqlExportWriter{
tableName: tableName,
sch: tt.sch,
wr: &stringWr,
}
for _, r := range tt.rows {
assert.NoError(t, w.WriteDeleteRow(context.Background(), r))
}
assert.Equal(t, tt.expectedOutput, stringWr.String())
})
}
}
func TestUpdateRow(t *testing.T) {
id := uuid.MustParse("00000000-0000-0000-0000-000000000000")
tableName := "people"
tests := []test{
{
name: "simple row",
rows: rs(dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie"))),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"some guy\",`age`=100,`is_married`=FALSE,`title`=\"normie\" WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");" + "\n",
},
{
name: "embedded quotes",
rows: rs(dtestutils.NewTypedRow(id, `It's "Mister Perfect" to you`, 100, false, strPointer("normie"))),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"It's \\\"Mister Perfect\\\" to you\",`age`=100,`is_married`=FALSE,`title`=\"normie\" WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");" + "\n",
},
{
name: "two rows",
rows: rs(
dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie")),
dtestutils.NewTypedRow(id, "guy personson", 0, true, strPointer("officially a person"))),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"some guy\",`age`=100,`is_married`=FALSE,`title`=\"normie\" WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");" + "\n" +
"UPDATE `people` SET `name`=\"guy personson\",`age`=0,`is_married`=TRUE,`title`=\"officially a person\" WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");" + "\n",
},
{
name: "null values",
rows: rs(dtestutils.NewTypedRow(id, "some guy", 100, false, nil)),
sch: dtestutils.TypedSchema,
expectedOutput: "UPDATE `people` SET `name`=\"some guy\",`age`=100,`is_married`=FALSE,`title`=NULL WHERE (`id`=\"00000000-0000-0000-0000-000000000000\");" + "\n",
},
}
trickySch := dtestutils.CreateSchema(
schema.NewColumn("a name with spaces", 0, types.FloatKind, false),
schema.NewColumn("anotherColumn", 1, types.IntKind, true),
)
tests = append(tests, test{
name: "negative values and columns with spaces",
rows: rs(dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42))),
sch: trickySch,
expectedOutput: "UPDATE `people` SET `a name with spaces`=-3.14 WHERE (`anotherColumn`=-42);" + "\n",
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var stringWr StringBuilderCloser
w := &SqlExportWriter{
tableName: tableName,
sch: tt.sch,
wr: &stringWr,
}
for _, r := range tt.rows {
assert.NoError(t, w.WriteUpdateRow(context.Background(), r))
}
assert.Equal(t, tt.expectedOutput, stringWr.String())
})
}
}
func TestEndToEnd(t *testing.T) {
id := uuid.MustParse("00000000-0000-0000-0000-000000000000")
tableName := "people"
dropCreateStatement := "DROP TABLE IF EXISTS `people`;\n" + sql.SchemaAsCreateStmt(tableName, dtestutils.TypedSchema)
dropCreateStatement := sql.TableDropIfExistsStmt(tableName) + "\n" + sql.SchemaAsCreateStmt(tableName, dtestutils.TypedSchema)
type test struct {
name string