Begin the pain

This commit is contained in:
Patrick O'brien 2016-08-14 07:23:36 +10:00 committed by Aaron L
parent 1875bac7cf
commit 160c6ff0f0
6 changed files with 34 additions and 112 deletions

View file

@ -3,7 +3,6 @@ package bdb
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"strings"
) )
var rgxAutoIncColumn = regexp.MustCompile(`^nextval\(.*\)`) var rgxAutoIncColumn = regexp.MustCompile(`^nextval\(.*\)`)
@ -90,28 +89,3 @@ func SQLColDefStrings(defs []SQLColumnDef) []string {
return strs return strs
} }
// AutoIncPrimaryKey returns the auto-increment primary key column name or an
// empty string.
func AutoIncPrimaryKey(cols []Column, pkey *PrimaryKey) *Column {
if pkey == nil {
return nil
}
for _, pkeyColumn := range pkey.Columns {
for _, c := range cols {
if c.Name != pkeyColumn {
continue
}
if !rgxAutoIncColumn.MatchString(c.Default) || c.Nullable ||
!(strings.HasPrefix(c.Type, "int") || strings.HasPrefix(c.Type, "uint")) {
continue
}
return &c
}
}
return nil
}

View file

@ -50,55 +50,3 @@ func TestSQLDefStrings(t *testing.T) {
t.Error("wrong str:", got) t.Error("wrong str:", got)
} }
} }
func TestAutoIncPrimaryKey(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Ok bool
Expect Column
Pkey *PrimaryKey
Columns []Column
}{
"nillcase": {
Ok: false,
Pkey: nil,
Columns: nil,
},
"easycase": {
Ok: true,
Expect: Column{Name: "one", Type: "int32", Nullable: false, Default: `nextval('abc'::regclass)`},
Pkey: &PrimaryKey{Name: "pkey", Columns: []string{"one"}},
Columns: []Column{{Name: "one", Type: "int32", Nullable: false, Default: `nextval('abc'::regclass)`}},
},
"missingcase": {
Ok: false,
Pkey: &PrimaryKey{Name: "pkey", Columns: []string{"two"}},
Columns: []Column{{Name: "one", Type: "int32", Nullable: false, Default: `nextval('abc'::regclass)`}},
},
"wrongtype": {
Ok: false,
Pkey: &PrimaryKey{Name: "pkey", Columns: []string{"one"}},
Columns: []Column{{Name: "one", Type: "string", Nullable: false, Default: `nextval('abc'::regclass)`}},
},
"nodefault": {
Ok: false,
Pkey: &PrimaryKey{Name: "pkey", Columns: []string{"one"}},
Columns: []Column{{Name: "one", Type: "string", Nullable: false, Default: ``}},
},
"nullable": {
Ok: false,
Pkey: &PrimaryKey{Name: "pkey", Columns: []string{"one"}},
Columns: []Column{{Name: "one", Type: "string", Nullable: true, Default: `nextval('abc'::regclass)`}},
},
}
for testName, test := range tests {
pkey := AutoIncPrimaryKey(test.Columns, test.Pkey)
if ok := (pkey != nil); ok != test.Ok {
t.Errorf("%s) found state was wrong, want: %t, got: %t", testName, test.Ok, ok)
} else if test.Ok && *pkey != test.Expect {
t.Errorf("%s) wrong primary key, want: %#v, got %#v", testName, test.Expect, pkey)
}
}
}

View file

@ -172,7 +172,6 @@ var templateFunctions = template.FuncMap{
"filterColumnsByAutoIncrement": bdb.FilterColumnsByAutoIncrement, "filterColumnsByAutoIncrement": bdb.FilterColumnsByAutoIncrement,
"filterColumnsByValidated": bdb.FilterColumnsByValidated, "filterColumnsByValidated": bdb.FilterColumnsByValidated,
"filterColumnsByUnique": bdb.FilterColumnsByUnique, "filterColumnsByUnique": bdb.FilterColumnsByUnique,
"autoIncPrimaryKey": bdb.AutoIncPrimaryKey,
"sqlColDefinitions": bdb.SQLColDefinitions, "sqlColDefinitions": bdb.SQLColDefinitions,
"sqlColDefStrings": bdb.SQLColDefStrings, "sqlColDefStrings": bdb.SQLColDefStrings,
"columnNames": bdb.ColumnNames, "columnNames": bdb.ColumnNames,

View file

@ -9,7 +9,7 @@ var (
{{$varNameSingular}}UniqueColumns = []string{{"{"}}{{.Table.Columns | filterColumnsByUnique | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}} {{$varNameSingular}}UniqueColumns = []string{{"{"}}{{.Table.Columns | filterColumnsByUnique | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
{{$varNameSingular}}PrimaryKeyColumns = []string{{"{"}}{{.Table.PKey.Columns | 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}}AutoIncrementColumns = []string{{"{"}}{{.Table.Columns | filterColumnsByAutoIncrement true | columnNames | stringMap .StringFuncs.quoteWrap | join "," }}{{"}"}}
{{$varNameSingular}}AutoIncPrimaryKey = "{{- with autoIncPrimaryKey .Table.Columns .Table.PKey -}}{{.Name}}{{- end -}}" {{$varNameSingular}}AutoIncPrimaryKeys = []string{{"{"}}{{.Table.Columns | filterColumnsByPrimaryKey .Table.PKey | filterColumnsByDefault true | columnNames | join ", "}}{{"}"}}
) )
type ( type (

View file

@ -41,34 +41,34 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
ins := fmt.Sprintf(`INSERT INTO {{.Table.Name}} ("%s") VALUES (%s)`, strings.Join(wl, `","`), strmangle.Placeholders(len(wl), 1, 1)) ins := fmt.Sprintf(`INSERT INTO {{.Table.Name}} ("%s") VALUES (%s)`, strings.Join(wl, `","`), strmangle.Placeholders(len(wl), 1, 1))
{{if driverUsesLastInsertID .DriverName}} {{if driverUsesLastInsertID .DriverName}}
if len(returnColumns) != 0 { if boil.DebugMode {
result, err := exec.Exec(ins, boil.GetStructValues(o, wl...)...) fmt.Fprintln(boil.DebugWriter, ins)
if err != nil { fmt.Fprintln(boil.DebugWriter, boil.GetStructValues(o, wl...))
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}") }
}
lastId, err := result.lastInsertId() result, err := exec.Exec(ins, boil.GetStructValues(o, wl...)...)
if err != nil || lastId == 0 { if err != nil {
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s`, strings.Join(returnColumns, `","`), strmangle.WhereClause(1, wl)) return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
rows, err := exec.Query(sel, boil.GetStructValues(o, wl...)...) }
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
}
defer rows.Close()
i := 0 if len(returnColumns) == 0 {
ptrs := boil.GetStructPointers(o, returnColumns...) return o.doAfterCreateHooks()
for rows.Next() { }
if err := rows.Scan(ptrs[i]); err != nil {
return errors.Wrapf(err, "{{.PkgName}}: unable to get result of insert, scan failed for column %s index %d\n\n%#v", returnColumns[i], i, ptrs) lastId, err := result.lastInsertId()
} if err != nil || lastId == 0 {
i++ return ErrSyncFail
} }
} else if {{$varNameSingular}}AutoIncPrimKey != "" {
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s=$1`, strings.Join(returnColumns, ","), {{$varNameSingular}}AutoIncPrimaryKey, lastId) if len({{$varNameSingular}}AutoIncPrimaryKeys) != 1 {
} return ErrSyncFail
} else { }
_, err = exec.Exec(ins, boil.GetStructValues(o, wl...)...)
pkey := {{$varNameSingular}}AutoIncPrimaryKeys[0]
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s`, strings.Join(returnColumns, `","`), strmangle.WhereClause(1, pkey))
err := exec.QueryRow(sel, lastId).Scan(boil.GetStructPointers(o, returnColumns...))
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
} }
{{else}} {{else}}
if len(returnColumns) != 0 { if len(returnColumns) != 0 {
@ -77,7 +77,6 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
} else { } else {
_, err = exec.Exec(ins, boil.GetStructValues(o, wl...)...) _, err = exec.Exec(ins, boil.GetStructValues(o, wl...)...)
} }
{{end}}
if boil.DebugMode { if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, ins) fmt.Fprintln(boil.DebugWriter, ins)
@ -87,12 +86,9 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
if err != nil { if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}") return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
} }
{{end}}
if err := o.doAfterCreateHooks(); err != nil { return o.doAfterCreateHooks()
return err
}
return nil
} }
// generateInsertColumns generates the whitelist columns and return columns for an insert statement // generateInsertColumns generates the whitelist columns and return columns for an insert statement

View file

@ -7,3 +7,8 @@ type upsertData struct {
whitelist []string whitelist []string
returning []string returning []string
} }
// ErrSyncFail occurs during insert when the record could not be retrieved in
// order to populate default value information. This usually happens when LastInsertId
// fails or there was a primary key configuration that was not resolvable.
var ErrSyncFail = errors.New("{{.PkgName}}: failed to synchronize data after insert")