Tweak MySQL type fit check
Make the check respect signed & unsigned as well as decimal and varchar sizes.
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package ddl
|
||||
|
||||
import "strings"
|
||||
|
||||
func ParseColumnTypes(c *Column) (original, name string, meta []string) {
|
||||
original = strings.ToLower(c.Type.Name)
|
||||
|
||||
pp := strings.Split(original, "(")
|
||||
name = pp[0]
|
||||
if len(pp) > 1 {
|
||||
meta = strings.Split(strings.TrimRight(pp[1], ")"), ",")
|
||||
for i, m := range meta {
|
||||
meta[i] = strings.TrimSpace(m)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -234,28 +234,29 @@ func (mysqlDialect) AttributeToColumn(attr *dal.Attribute) (col *ddl.Column, err
|
||||
}
|
||||
|
||||
func (mysqlDialect) ColumnFits(target, assert *ddl.Column) bool {
|
||||
targetType := strings.ToLower(target.Type.Name)
|
||||
assertType := strings.ToLower(assert.Type.Name)
|
||||
|
||||
if targetType == "bigint unsigned" {
|
||||
targetType = "bigint"
|
||||
}
|
||||
if assertType == "bigint unsigned" {
|
||||
assertType = "bigint"
|
||||
}
|
||||
|
||||
targetType = strings.Split(targetType, "(")[0]
|
||||
assertType = strings.Split(assertType, "(")[0]
|
||||
targetType, targetName, targetMeta := ddl.ParseColumnTypes(target)
|
||||
assertType, assertName, assertMeta := ddl.ParseColumnTypes(assert)
|
||||
|
||||
// If everything matches up perfectly use that
|
||||
if assertType == targetType {
|
||||
return true
|
||||
}
|
||||
|
||||
// @todo check varchar sizes
|
||||
// @todo signed & unsigned
|
||||
|
||||
// See if we can guess it
|
||||
// [the type of the target column][what types fit the target col. type]
|
||||
return map[string]map[string]bool{
|
||||
matches := map[string]map[string]bool{
|
||||
"bigint unsigned": {
|
||||
"varchar": true,
|
||||
"text": true,
|
||||
|
||||
"decimal": true,
|
||||
},
|
||||
"bigint signed": {
|
||||
"varchar": true,
|
||||
"text": true,
|
||||
|
||||
"decimal": true,
|
||||
},
|
||||
"bigint": {
|
||||
"varchar": true,
|
||||
"text": true,
|
||||
@@ -300,7 +301,22 @@ func (mysqlDialect) ColumnFits(target, assert *ddl.Column) bool {
|
||||
"varchar": true,
|
||||
"text": true,
|
||||
},
|
||||
}[assertType][targetType]
|
||||
}
|
||||
|
||||
baseMatch := matches[assertName][targetName]
|
||||
|
||||
// Special cases
|
||||
switch {
|
||||
case assertName == "varchar" && targetName == "varchar":
|
||||
// Check varchar size
|
||||
return baseMatch && assertMeta[0] <= targetMeta[0]
|
||||
|
||||
case assertName == "decimal" && targetName == "decimal":
|
||||
// Check decimal size and precision
|
||||
return baseMatch && assertMeta[0] <= targetMeta[0] && assertMeta[1] <= targetMeta[1]
|
||||
}
|
||||
|
||||
return baseMatch
|
||||
}
|
||||
|
||||
func (d mysqlDialect) ExprHandler(n *ql.ASTNode, args ...exp.Expression) (expr exp.Expression, err error) {
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/store/adapters/rdbms/ddl"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestColumnFits(t *testing.T) {
|
||||
tcc := []struct {
|
||||
name string
|
||||
target *ddl.Column
|
||||
assert *ddl.Column
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "exact match (text)",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "text",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "text",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "fits somewhere",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "text",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "decimal(1,2)",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "doesn't fit",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "decimal(1,2)",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "text",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "decimal fits",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "decimal(1,2)",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "decimal(1,2)",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "decimal doesn't fit",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "decimal(1,2)",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "decimal(2,3)",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: "varchar fits",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "varchar(42)",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "varchar(42)",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "varchar doesn't fit",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "varchar(42)",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "varchar(84)",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: "sneaking unsigned into signed",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "bigint signed",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "bigint unsigned",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "sneaking signed into unsigned",
|
||||
target: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "bigint unsigned",
|
||||
},
|
||||
},
|
||||
assert: &ddl.Column{
|
||||
Type: &ddl.ColumnType{
|
||||
Name: "bigint signed",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
d := mysqlDialect{}
|
||||
|
||||
for _, c := range tcc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
out := d.ColumnFits(c.target, c.assert)
|
||||
assert.Equal(t, c.expected, out)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user