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 (
"fmt"
"regexp"
"strings"
)
var rgxAutoIncColumn = regexp.MustCompile(`^nextval\(.*\)`)
@ -90,28 +89,3 @@ func SQLColDefStrings(defs []SQLColumnDef) []string {
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)
}
}
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,
"filterColumnsByValidated": bdb.FilterColumnsByValidated,
"filterColumnsByUnique": bdb.FilterColumnsByUnique,
"autoIncPrimaryKey": bdb.AutoIncPrimaryKey,
"sqlColDefinitions": bdb.SQLColDefinitions,
"sqlColDefStrings": bdb.SQLColDefStrings,
"columnNames": bdb.ColumnNames,

View file

@ -9,7 +9,7 @@ var (
{{$varNameSingular}}UniqueColumns = []string{{"{"}}{{.Table.Columns | filterColumnsByUnique | 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 -}}"
{{$varNameSingular}}AutoIncPrimaryKeys = []string{{"{"}}{{.Table.Columns | filterColumnsByPrimaryKey .Table.PKey | filterColumnsByDefault true | columnNames | join ", "}}{{"}"}}
)
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))
{{if driverUsesLastInsertID .DriverName}}
if len(returnColumns) != 0 {
result, err := exec.Exec(ins, boil.GetStructValues(o, wl...)...)
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, ins)
fmt.Fprintln(boil.DebugWriter, boil.GetStructValues(o, wl...))
}
lastId, err := result.lastInsertId()
if err != nil || lastId == 0 {
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s`, strings.Join(returnColumns, `","`), strmangle.WhereClause(1, wl))
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()
result, err := exec.Exec(ins, boil.GetStructValues(o, wl...)...)
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
}
i := 0
ptrs := boil.GetStructPointers(o, returnColumns...)
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)
}
i++
}
} else if {{$varNameSingular}}AutoIncPrimKey != "" {
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s=$1`, strings.Join(returnColumns, ","), {{$varNameSingular}}AutoIncPrimaryKey, lastId)
}
} else {
_, err = exec.Exec(ins, boil.GetStructValues(o, wl...)...)
if len(returnColumns) == 0 {
return o.doAfterCreateHooks()
}
lastId, err := result.lastInsertId()
if err != nil || lastId == 0 {
return ErrSyncFail
}
if len({{$varNameSingular}}AutoIncPrimaryKeys) != 1 {
return ErrSyncFail
}
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}}
if len(returnColumns) != 0 {
@ -77,7 +77,6 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
} else {
_, err = exec.Exec(ins, boil.GetStructValues(o, wl...)...)
}
{{end}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, ins)
@ -87,12 +86,9 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
}
{{end}}
if err := o.doAfterCreateHooks(); err != nil {
return err
}
return nil
return o.doAfterCreateHooks()
}
// generateInsertColumns generates the whitelist columns and return columns for an insert statement

View file

@ -7,3 +7,8 @@ type upsertData struct {
whitelist []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")