Add provision for enforced types, eg uuid
* Add enforced to column data * Add enforced list to driver * Fix bug in TitleCase (now uses regexp) * Fix broken zero-value enforced type inserts by using RandomizeEnforcedStruct
This commit is contained in:
parent
39fe91f2cb
commit
c7c0fe5c0d
10 changed files with 69 additions and 20 deletions
|
@ -17,6 +17,7 @@ type Column struct {
|
|||
Default string
|
||||
Nullable bool
|
||||
Unique bool
|
||||
Enforced bool
|
||||
}
|
||||
|
||||
// ColumnNames of the columns.
|
||||
|
@ -64,12 +65,12 @@ func FilterColumnsByDefault(defaults bool, columns []Column) []Column {
|
|||
}
|
||||
|
||||
// FilterColumnsBySimpleDefault generates a list of columns that have simple default values
|
||||
// A simple default value is one without a function call
|
||||
// A simple default value is one without a function call and a non-enforced type
|
||||
func FilterColumnsBySimpleDefault(columns []Column) []Column {
|
||||
var cols []Column
|
||||
|
||||
for _, c := range columns {
|
||||
if len(c.Default) != 0 && !strings.ContainsAny(c.Default, "()") {
|
||||
if len(c.Default) != 0 && !strings.ContainsAny(c.Default, "()") && !c.Enforced {
|
||||
cols = append(cols, c)
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +92,19 @@ func FilterColumnsByAutoIncrement(autos bool, columns []Column) []Column {
|
|||
return cols
|
||||
}
|
||||
|
||||
// FilterColumnsByEnforced generates the list of enforced columns
|
||||
func FilterColumnsByEnforced(columns []Column) []Column {
|
||||
var cols []Column
|
||||
|
||||
for _, c := range columns {
|
||||
if c.Enforced == true {
|
||||
cols = append(cols, c)
|
||||
}
|
||||
}
|
||||
|
||||
return cols
|
||||
}
|
||||
|
||||
var (
|
||||
rgxRawDefaultValue = regexp.MustCompile(`'(.*)'::`)
|
||||
rgxBoolDefaultValue = regexp.MustCompile(`(?i)true|false`)
|
||||
|
|
|
@ -17,6 +17,9 @@ type PostgresDriver struct {
|
|||
dbConn *sql.DB
|
||||
}
|
||||
|
||||
// enforcedTypes are types that cannot be zero values in the database.
|
||||
var enforcedTypes = []string{"uuid"}
|
||||
|
||||
// NewPostgresDriver takes the database connection details as parameters and
|
||||
// returns a pointer to a PostgresDriver object. Note that it is required to
|
||||
// call PostgresDriver.Open() and PostgresDriver.Close() to open and close
|
||||
|
@ -142,6 +145,7 @@ func (p *PostgresDriver) Columns(tableName string) ([]bdb.Column, error) {
|
|||
Default: colDefault,
|
||||
Nullable: nullable == "YES",
|
||||
Unique: unique,
|
||||
Enforced: isEnforced(colType),
|
||||
}
|
||||
columns = append(columns, column)
|
||||
}
|
||||
|
@ -293,3 +297,14 @@ func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column {
|
|||
|
||||
return c
|
||||
}
|
||||
|
||||
// isEnforced checks if the database type is in the enforcedTypes list.
|
||||
func isEnforced(typ string) bool {
|
||||
for _, v := range enforcedTypes {
|
||||
if v == typ {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -33,8 +33,6 @@ var (
|
|||
typeTime = reflect.TypeOf(time.Time{})
|
||||
|
||||
rgxValidTime = regexp.MustCompile(`[2-9]+`)
|
||||
|
||||
enforcedTypes = []string{"uuid"}
|
||||
)
|
||||
|
||||
type seed int
|
||||
|
@ -204,13 +202,17 @@ func RandomizeStruct(str interface{}, colTypes map[string]string, includeInvalid
|
|||
return nil
|
||||
}
|
||||
|
||||
func RandomizeEnforcedStruct(obj interface{}, colTypes map[string]string) error {
|
||||
value := reflect.Indirect(reflect.ValueOf(obj))
|
||||
if !value.IsValid() {
|
||||
return fmt.Errorf("Invalid object provided: %T", obj)
|
||||
func RandomizeEnforcedStruct(obj interface{}, enforcedCols []string, colTypes map[string]string) error {
|
||||
// Check if it's pointer
|
||||
value := reflect.ValueOf(obj)
|
||||
kind := value.Kind()
|
||||
if kind != reflect.Ptr {
|
||||
return fmt.Errorf("Outer element should be a pointer, given a non-pointer: %T", obj)
|
||||
}
|
||||
|
||||
kind := value.Kind()
|
||||
// Check if it's a struct
|
||||
value = value.Elem()
|
||||
kind = value.Kind()
|
||||
if kind != reflect.Struct {
|
||||
return fmt.Errorf("Inner element should be a struct, given a non-struct: %T", obj)
|
||||
}
|
||||
|
@ -222,9 +224,9 @@ func RandomizeEnforcedStruct(obj interface{}, colTypes map[string]string) error
|
|||
for i := 0; i < nFields; i++ {
|
||||
fieldVal := value.Field(i)
|
||||
fieldTyp := typ.Field(i)
|
||||
for _, v := range enforcedTypes {
|
||||
if colTypes[fieldTyp.Name] == v {
|
||||
if err := randomizeField(fieldVal, v, false); err != nil {
|
||||
for _, v := range enforcedCols {
|
||||
if strmangle.TitleCase(v) == fieldTyp.Name {
|
||||
if err := randomizeField(fieldVal, colTypes[fieldTyp.Name], false); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
|
|
@ -201,6 +201,10 @@ func TestRandomizeEnforcedStruct(t *testing.T) {
|
|||
UUID2 string
|
||||
}{}
|
||||
|
||||
enforcedCols := []string{
|
||||
"uuid1",
|
||||
"uuid2",
|
||||
}
|
||||
fieldTypes := map[string]string{
|
||||
"Int": "integer",
|
||||
"NullInt": "integer",
|
||||
|
@ -208,7 +212,7 @@ func TestRandomizeEnforcedStruct(t *testing.T) {
|
|||
"UUID2": "uuid",
|
||||
}
|
||||
|
||||
err := RandomizeEnforcedStruct(&testStruct, fieldTypes)
|
||||
err := RandomizeEnforcedStruct(&testStruct, enforcedCols, fieldTypes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -15,8 +15,15 @@ import (
|
|||
|
||||
var (
|
||||
idAlphabet = []byte("abcdefghijklmnopqrstuvwxyz")
|
||||
uppercaseWords = []string{"id", "uid", "uuid", "guid", "ssn", "tz"}
|
||||
smartQuoteRgx = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(\."?[_a-z][_a-z0-9]*"?)*$`)
|
||||
uppercaseWords = []*regexp.Regexp{
|
||||
regexp.MustCompile(`^id[0-9]*$`),
|
||||
regexp.MustCompile(`^uid[0-9]*$`),
|
||||
regexp.MustCompile(`^uuid[0-9]*$`),
|
||||
regexp.MustCompile(`^guid[0-9]*$`),
|
||||
regexp.MustCompile(`^ssn[0-9]*$`),
|
||||
regexp.MustCompile(`^tz[0-9]*$`),
|
||||
}
|
||||
smartQuoteRgx = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(\."?[_a-z][_a-z0-9]*"?)*$`)
|
||||
)
|
||||
|
||||
// IdentQuote attempts to quote simple identifiers in SQL tatements
|
||||
|
@ -90,8 +97,8 @@ func TitleCase(name string) string {
|
|||
for i, split := range splits {
|
||||
found := false
|
||||
for _, uc := range uppercaseWords {
|
||||
if split == uc {
|
||||
splits[i] = strings.ToUpper(uc)
|
||||
if uc.MatchString(split) {
|
||||
splits[i] = strings.ToUpper(split)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
@ -122,8 +129,8 @@ func CamelCase(name string) string {
|
|||
found := false
|
||||
if i > 0 {
|
||||
for _, uc := range uppercaseWords {
|
||||
if split == uc {
|
||||
splits[i] = strings.ToUpper(uc)
|
||||
if uc.MatchString(split) {
|
||||
splits[i] = strings.ToUpper(split)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -168,6 +168,7 @@ var templateFunctions = template.FuncMap{
|
|||
"filterColumnsByDefault": bdb.FilterColumnsByDefault,
|
||||
"filterColumnsBySimpleDefault": bdb.FilterColumnsBySimpleDefault,
|
||||
"filterColumnsByAutoIncrement": bdb.FilterColumnsByAutoIncrement,
|
||||
"filterColumnsByEnforced": bdb.FilterColumnsByEnforced,
|
||||
"autoIncPrimaryKey": bdb.AutoIncPrimaryKey,
|
||||
"sqlColDefinitions": bdb.SQLColDefinitions,
|
||||
"sqlColDefStrings": bdb.SQLColDefStrings,
|
||||
|
|
|
@ -5,6 +5,7 @@ var (
|
|||
{{$varNameSingular}}ColumnsWithoutDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
|
||||
{{$varNameSingular}}ColumnsWithDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
|
||||
{{$varNameSingular}}ColumnsWithSimpleDefault = []string{{"{"}}{{.Table.Columns | filterColumnsBySimpleDefault | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
|
||||
{{$varNameSingular}}ColumnsEnforced = []string{{"{"}}{{.Table.Columns | filterColumnsByEnforced | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
|
||||
{{$varNameSingular}}PrimaryKeyColumns = []string{{"{"}}{{.Table.PKey.Columns | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
|
||||
{{$varNameSingular}}AutoIncrementColumns = []string{{"{"}}{{.Table.Columns | filterColumnsByAutoIncrement true | columnNames | stringMap .StringFuncs.quoteWrap | join "," }}{{"}"}}
|
||||
{{$varNameSingular}}AutoIncPrimaryKey = "{{- with autoIncPrimaryKey .Table.Columns .Table.PKey -}}{{.Name}}{{- end -}}"
|
||||
|
|
|
@ -37,6 +37,7 @@ func Test{{$tableNamePlural}}Insert(t *testing.T) {
|
|||
{{$varNamePlural}}DeleteAllRows(t)
|
||||
|
||||
item := &{{$tableNameSingular}}{}
|
||||
boil.RandomizeEnforcedStruct(item, {{$varNameSingular}}ColumnsEnforced, {{$varNameSingular}}DBTypes)
|
||||
if err = item.InsertG(); err != nil {
|
||||
t.Errorf("Unable to insert zero-value item {{$tableNameSingular}}:\n%#v\nErr: %s", item, err)
|
||||
}
|
||||
|
@ -67,6 +68,9 @@ func Test{{$tableNamePlural}}Insert(t *testing.T) {
|
|||
|
||||
regularCols := []string{{"{"}}{{.Table.Columns | filterColumnsByAutoIncrement false | filterColumnsByDefault false | columnNames | stringMap $parent.StringFuncs.quoteWrap | join ", "}}{{"}"}}
|
||||
|
||||
// Remove the enforced columns, they can never be zero values
|
||||
regularCols = boil.SetComplement(regularCols, {{$varNameSingular}}ColumnsEnforced)
|
||||
|
||||
// Ensure the non-defaultvalue columns and non-autoincrement columns are stored correctly as zero or null values.
|
||||
for _, c := range regularCols {
|
||||
rv := reflect.Indirect(reflect.ValueOf(item))
|
||||
|
|
|
@ -7,6 +7,7 @@ func Test{{$tableNamePlural}}Update(t *testing.T) {
|
|||
var err error
|
||||
|
||||
item := {{$tableNameSingular}}{}
|
||||
boil.RandomizeEnforcedStruct(&item, {{$varNameSingular}}ColumnsEnforced, {{$varNameSingular}}DBTypes)
|
||||
if err = item.InsertG(); err != nil {
|
||||
t.Errorf("Unable to insert zero-value item {{$tableNameSingular}}:\n%#v\nErr: %s", item, err)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ func textsFromForeignKey(packageName string, tables []bdb.Table, table bdb.Table
|
|||
|
||||
r.ForeignTable.Name = fkey.ForeignTable
|
||||
r.ForeignTable.NameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignTable))
|
||||
r.ForeignTable.NamePluralGo = strmangle.TitleCase(fkey.ForeignTable)
|
||||
r.ForeignTable.NamePluralGo = strmangle.TitleCase(strmangle.Plural(fkey.ForeignTable))
|
||||
r.ForeignTable.ColumnName = fkey.ForeignColumn
|
||||
r.ForeignTable.ColumnNameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignColumn))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue