From ed423a360605cf1d4309cc78d969fce5674d7aea Mon Sep 17 00:00:00 2001 From: Alex Grintsvayg Date: Mon, 12 Jun 2017 14:02:04 -0400 Subject: [PATCH] detect autoincrement column, fix lastID in upsert when update doesnt change anything --- bdb/drivers/mock.go | 4 ++++ bdb/drivers/mssql.go | 4 ++++ bdb/drivers/mysql.go | 32 ++++++++++++++++++++++++++++++++ bdb/drivers/postgres.go | 4 ++++ bdb/interface.go | 5 +++++ bdb/table.go | 4 +++- main.go | 6 +++--- queries/query_builders.go | 7 ++++++- templates/01_types.tpl | 1 + templates/17_upsert.tpl | 2 +- 10 files changed, 63 insertions(+), 6 deletions(-) diff --git a/bdb/drivers/mock.go b/bdb/drivers/mock.go index 810eb48..d8a5aa0 100644 --- a/bdb/drivers/mock.go +++ b/bdb/drivers/mock.go @@ -62,6 +62,10 @@ func (m *MockDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, e return []bdb.UniqueKey{}, nil } +func (m *MockDriver) AutoincrementInfo(schema, tableName string) (string, error) { + return "", nil +} + // ForeignKeyInfo returns a list of mock foreignkeys func (m *MockDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) { return map[string][]bdb.ForeignKey{ diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go index 70b9ed9..79f3010 100644 --- a/bdb/drivers/mssql.go +++ b/bdb/drivers/mssql.go @@ -245,6 +245,10 @@ func (m *MSSQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, return []bdb.UniqueKey{}, errors.New("not implemented") } +func (m *MSSQLDriver) AutoincrementInfo(schema, tableName string) (string, error) { + return "", errors.New("not implemented") +} + // ForeignKeyInfo retrieves the foreign keys for a given table name. func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) { var fkeys []bdb.ForeignKey diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go index 6a20ba0..41510ee 100644 --- a/bdb/drivers/mysql.go +++ b/bdb/drivers/mysql.go @@ -272,6 +272,38 @@ func (m *MySQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, return ukeys, nil } +// AutoincrementInfo retrieves the autoincrement column for a given table name, if one exists. +func (m *MySQLDriver) AutoincrementInfo(schema, tableName string) (string, error) { + query := ` + select column_name + from information_schema.columns + where table_schema = ? and table_name = ? and extra like "%auto_increment%" + ` + + var rows *sql.Rows + var err error + if rows, err = m.dbConn.Query(query, schema, tableName); err != nil { + return "", err + } + + for rows.Next() { + var column string + + err = rows.Scan(&column) + if err != nil { + return "", err + } + + return column, nil + } + + if err = rows.Err(); err != nil { + return "", err + } + + return "", nil +} + // ForeignKeyInfo retrieves the foreign keys for a given table name. func (m *MySQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) { var fkeys []bdb.ForeignKey diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go index 4b6a9f4..9af7edd 100644 --- a/bdb/drivers/postgres.go +++ b/bdb/drivers/postgres.go @@ -270,6 +270,10 @@ func (p *PostgresDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKe return []bdb.UniqueKey{}, errors.New("not implemented") } +func (p *PostgresDriver) AutoincrementInfo(schema, tableName string) (string, error) { + return "", errors.New("not implemented") +} + // ForeignKeyInfo retrieves the foreign keys for a given table name. func (p *PostgresDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) { var fkeys []bdb.ForeignKey diff --git a/bdb/interface.go b/bdb/interface.go index 1fe179a..7f4baa5 100644 --- a/bdb/interface.go +++ b/bdb/interface.go @@ -10,6 +10,7 @@ type Interface interface { Columns(schema, tableName string) ([]Column, error) PrimaryKeyInfo(schema, tableName string) (*PrimaryKey, error) UniqueKeyInfo(schema, tableName string) ([]UniqueKey, error) + AutoincrementInfo(schema, tableName string) (string, error) ForeignKeyInfo(schema, tableName string) ([]ForeignKey, error) // TranslateColumnType takes a Database column type and returns a go column type. @@ -72,6 +73,10 @@ func Tables(db Interface, schema string, whitelist, blacklist []string) ([]Table return nil, errors.Wrapf(err, "unable to fetch table fkey info (%s)", name) } + if t.AutoIncrementColumn, err = db.AutoincrementInfo(schema, name); err != nil { + return nil, errors.Wrapf(err, "unable to fetch table autoincrement info (%s)", name) + } + setIsJoinTable(&t) tables = append(tables, t) diff --git a/bdb/table.go b/bdb/table.go index d5cbb50..13355aa 100644 --- a/bdb/table.go +++ b/bdb/table.go @@ -8,7 +8,9 @@ type Table struct { // For dbs with real schemas, like Postgres. // Example value: "schema_name"."table_name" SchemaName string - Columns []Column + + Columns []Column + AutoIncrementColumn string PKey *PrimaryKey UKeys []UniqueKey diff --git a/main.go b/main.go index 5103116..8344e57 100644 --- a/main.go +++ b/main.go @@ -8,13 +8,13 @@ import ( "strings" "github.com/kat-co/vala" - "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/lbryio/sqlboiler/bdb/drivers" "github.com/lbryio/sqlboiler/boilingcore" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) -const sqlBoilerVersion = "2.3.0" +const sqlBoilerVersion = "2.4.0+lbry" var ( cmdState *boilingcore.State diff --git a/queries/query_builders.go b/queries/query_builders.go index d221aca..f884f91 100644 --- a/queries/query_builders.go +++ b/queries/query_builders.go @@ -190,7 +190,7 @@ func buildUpdateQuery(q *Query) (*bytes.Buffer, []interface{}) { } // BuildUpsertQueryMySQL builds a SQL statement string using the upsertData provided. -func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []string) string { +func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []string, autoIncrementCol string) string { whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist) buf := strmangle.GetBuffer() @@ -220,6 +220,11 @@ func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []st strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1), ) + // https://stackoverflow.com/questions/778534/mysql-on-duplicate-key-last-insert-id + if autoIncrementCol != "" { + buf.WriteString(autoIncrementCol + " = LAST_INSERT_ID(" + autoIncrementCol + "), ") + } + for i, v := range update { if i != 0 { buf.WriteByte(',') diff --git a/templates/01_types.tpl b/templates/01_types.tpl index 9340e42..5aac35f 100644 --- a/templates/01_types.tpl +++ b/templates/01_types.tpl @@ -10,6 +10,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}}PrimaryKeyColumns = []string{{"{"}}{{.Table.PKey.Columns | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}} + {{$varNameSingular}}AutoIncrementColumn = "{{.Table.AutoIncrementColumn }}" ) type ( diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl index f3d51e7..dbce58c 100644 --- a/templates/17_upsert.tpl +++ b/templates/17_upsert.tpl @@ -115,7 +115,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName } cache.query = queries.BuildUpsertQueryPostgres(dialect, "{{$schemaTable}}", updateOnConflict, ret, update, conflict, insert) {{else if eq .DriverName "mysql"}} - cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, insert) + cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, insert, {{$varNameSingular}}AutoIncrementColumn) cache.retQuery = fmt.Sprintf( "SELECT %s FROM {{.LQ}}{{.Table.Name}}{{.RQ}} WHERE {{whereClause .LQ .RQ 0 .Table.PKey.Columns}}", strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, ret), ","),