From b85774b8cdff90a7e8c400f919eba523989e6994 Mon Sep 17 00:00:00 2001 From: Pete Demoreuille Date: Thu, 16 Jan 2014 14:02:10 -0800 Subject: [PATCH 1/9] Handle int8/uint8 (and unsigned types on mysql) Naive handling of int8/uint8 for postgres/sqlite, for Mysql use tinyint/smallint/int/bigint appropriately, and create the columns as unsigned for Uint8/Uint16/Uint/Uint32/Uint64. --- dialect.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dialect.go b/dialect.go index 74c914ca..d7438592 100644 --- a/dialect.go +++ b/dialect.go @@ -75,7 +75,7 @@ func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) return d.ToSqlType(val.Elem(), maxsize, isAutoIncr) case reflect.Bool: return "integer" - case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint16, reflect.Uint32, reflect.Uint64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return "integer" case reflect.Float64, reflect.Float32: return "real" @@ -161,7 +161,7 @@ func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr boo return d.ToSqlType(val.Elem(), maxsize, isAutoIncr) case reflect.Bool: return "boolean" - case reflect.Int, reflect.Int16, reflect.Int32, reflect.Uint16, reflect.Uint32: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32: if isAutoIncr { return "serial" } @@ -275,10 +275,22 @@ func (m MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) return m.ToSqlType(val.Elem(), maxsize, isAutoIncr) case reflect.Bool: return "boolean" - case reflect.Int, reflect.Int16, reflect.Int32, reflect.Uint16, reflect.Uint32: + case reflect.Int8: + return "tinyint" + case reflect.Uint8: + return "tinyint unsigned" + case reflect.Int16: + return "smallint" + case reflect.Uint16: + return "smallint unsigned" + case reflect.Int, reflect.Int32: return "int" - case reflect.Int64, reflect.Uint64: + case reflect.Uint, reflect.Uint32: + return "int unsigned" + case reflect.Int64: return "bigint" + case reflect.Uint64: + return "bigint unsigned" case reflect.Float64, reflect.Float32: return "double" case reflect.Slice: From b6083a5f44ea82b393f4943787281bf063130534 Mon Sep 17 00:00:00 2001 From: James Cooper Date: Sat, 18 Jan 2014 09:29:17 -0800 Subject: [PATCH 2/9] added contributor section to README --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 4e63eca8..e7bb424b 100644 --- a/README.md +++ b/README.md @@ -627,6 +627,18 @@ locally to test the library. gorp uses reflection to construct SQL queries and bind parameters. See the BenchmarkNativeCrud vs BenchmarkGorpCrud in gorp_test.go for a simple perf test. On my MacBook Pro gorp is about 2-3% slower than hand written SQL. +## Pull requests / Contributions + +Contributions are very welcome. Please follow these guidelines: + +* Fork the `develop` branch and issue pull requests targeting the `develop` branch + * If you don't do this, I'll likely cherry pick your commit into develop +* If you are adding an enhancement, please open an issue first with your proposed change. +* Changes that break backwards compatibility in the public API are only accepted after we + discuss on a GitHub issue for a while. + +Thanks! + ## Contributors * matthias-margush - column aliasing via tags From 7087b05a309841b237ecac211dc8f9bae2498d24 Mon Sep 17 00:00:00 2001 From: Pete Demoreuille Date: Sun, 23 Feb 2014 21:29:48 -0800 Subject: [PATCH 3/9] Don't create single-used prepared statements for Exec inside a txn --- gorp.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/gorp.go b/gorp.go index 02c33444..5df23537 100644 --- a/gorp.go +++ b/gorp.go @@ -978,7 +978,7 @@ func (m *DbMap) Select(i interface{}, query string, args ...interface{}) ([]inte } // Exec runs an arbitrary SQL statement. args represent the bind parameters. -// This is equivalent to running: Prepare(), Exec() using database/sql +// This is equivalent to running: Exec() using database/sql func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) { m.trace(query, args) //stmt, err := m.Db.Prepare(query) @@ -1122,12 +1122,7 @@ func (t *Transaction) Select(i interface{}, query string, args ...interface{}) ( // Exec has the same behavior as DbMap.Exec(), but runs in a transaction. func (t *Transaction) Exec(query string, args ...interface{}) (sql.Result, error) { t.dbmap.trace(query, args) - stmt, err := t.tx.Prepare(query) - if err != nil { - return nil, err - } - defer stmt.Close() - return stmt.Exec(args...) + return t.tx.Exec(query, args...) } // SelectInt is a convenience wrapper around the gorp.SelectInt function. From 9799a8ff21403bfe6f277a940e9f716fa0043dfa Mon Sep 17 00:00:00 2001 From: James Cooper Date: Wed, 26 Feb 2014 06:00:11 -0800 Subject: [PATCH 4/9] DbMap.Exec - remove commented code (related to #141) --- gorp.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gorp.go b/gorp.go index 5df23537..1829f267 100644 --- a/gorp.go +++ b/gorp.go @@ -981,11 +981,6 @@ func (m *DbMap) Select(i interface{}, query string, args ...interface{}) ([]inte // This is equivalent to running: Exec() using database/sql func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) { m.trace(query, args) - //stmt, err := m.Db.Prepare(query) - //if err != nil { - // return nil, err - //} - //fmt.Println("Exec", query, args) return m.Db.Exec(query, args...) } From ce736129edc9a02cd0e0d18a6ad12b78f1204354 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 22 Jan 2014 10:30:13 -0800 Subject: [PATCH 5/9] Merge of #127 from @dvander --- gorp.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gorp.go b/gorp.go index 1829f267..da298330 100644 --- a/gorp.go +++ b/gorp.go @@ -980,7 +980,7 @@ func (m *DbMap) Select(i interface{}, query string, args ...interface{}) ([]inte // Exec runs an arbitrary SQL statement. args represent the bind parameters. // This is equivalent to running: Exec() using database/sql func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) { - m.trace(query, args) + m.trace(query, args...) return m.Db.Exec(query, args...) } @@ -1072,12 +1072,12 @@ func (m *DbMap) tableForPointer(ptr interface{}, checkPK bool) (*TableMap, refle } func (m *DbMap) queryRow(query string, args ...interface{}) *sql.Row { - m.trace(query, args) + m.trace(query, args...) return m.Db.QueryRow(query, args...) } func (m *DbMap) query(query string, args ...interface{}) (*sql.Rows, error) { - m.trace(query, args) + m.trace(query, args...) return m.Db.Query(query, args...) } @@ -1116,7 +1116,7 @@ func (t *Transaction) Select(i interface{}, query string, args ...interface{}) ( // Exec has the same behavior as DbMap.Exec(), but runs in a transaction. func (t *Transaction) Exec(query string, args ...interface{}) (sql.Result, error) { - t.dbmap.trace(query, args) + t.dbmap.trace(query, args...) return t.tx.Exec(query, args...) } @@ -1208,12 +1208,12 @@ func (t *Transaction) ReleaseSavepoint(savepoint string) error { } func (t *Transaction) queryRow(query string, args ...interface{}) *sql.Row { - t.dbmap.trace(query, args) + t.dbmap.trace(query, args...) return t.tx.QueryRow(query, args...) } func (t *Transaction) query(query string, args ...interface{}) (*sql.Rows, error) { - t.dbmap.trace(query, args) + t.dbmap.trace(query, args...) return t.tx.Query(query, args...) } From 8dbc907c89a4733c61dc3aa7f06c8871a83047e0 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 28 Jan 2014 13:23:24 +1100 Subject: [PATCH 6/9] error instead of panicing in tableFor --- gorp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gorp.go b/gorp.go index da298330..5ba0ba37 100644 --- a/gorp.go +++ b/gorp.go @@ -1032,7 +1032,7 @@ func (m *DbMap) Begin() (*Transaction, error) { func (m *DbMap) tableFor(t reflect.Type, checkPK bool) (*TableMap, error) { table := tableOrNil(m, t) if table == nil { - panic(fmt.Sprintf("No table found for type: %v", t.Name())) + return nil, errors.New(fmt.Sprintf("No table found for type: %v", t.Name())) } if checkPK && len(table.keys) < 1 { From 415e4fc229e49c5d02a985887bcc4a2304dbdba4 Mon Sep 17 00:00:00 2001 From: James Cooper Date: Wed, 26 Feb 2014 06:47:39 -0800 Subject: [PATCH 7/9] #138 - fix spelling of services --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d9e0e34b..3fa139d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ go: - 1.1 - tip -servies: +services: - mysql - postgres - sqlite3 From 4efe0a58b0dcfde45c3aa4b8f7be5762101080e0 Mon Sep 17 00:00:00 2001 From: yz0075 Date: Sun, 12 Jan 2014 19:56:44 -0800 Subject: [PATCH 8/9] Added types for Null* from database/sql Added types for Null* from database/sql and changed "double" to "real" for postgres val.Name() switch. --- dialect.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dialect.go b/dialect.go index d7438592..ebb15d89 100644 --- a/dialect.go +++ b/dialect.go @@ -86,11 +86,11 @@ func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) } switch val.Name() { - case "NullableInt64": + case "NullableInt64", "NullInt64": return "integer" - case "NullableFloat64": + case "NullableFloat64", "NullFloat64": return "real" - case "NullableBool": + case "NullableBool", "NullBool": return "integer" case "NullableBytes": return "blob" @@ -180,11 +180,11 @@ func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr boo } switch val.Name() { - case "NullableInt64": + case "NullableInt64", "NullInt64": return "bigint" - case "NullableFloat64": - return "double" - case "NullableBool": + case "NullableFloat64", "NullFloat64": + return "real" + case "NullableBool", "NullBool": return "smallint" case "NullableBytes": return "bytea" @@ -300,11 +300,11 @@ func (m MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) } switch val.Name() { - case "NullableInt64": + case "NullableInt64", "NullInt64": return "bigint" - case "NullableFloat64": + case "NullableFloat64", "NullFloat64": return "double" - case "NullableBool": + case "NullableBool", "NullBool": return "tinyint" case "NullableBytes": return "mediumblob" From 30f5a47e7a7fb0e0f9b616502e0f316c66cdee70 Mon Sep 17 00:00:00 2001 From: James Cooper Date: Wed, 26 Feb 2014 15:30:43 -0800 Subject: [PATCH 9/9] #121 - cleanup old Nullable* strings. Use "double precision" for float64 with postgres. --- dialect.go | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/dialect.go b/dialect.go index ebb15d89..6b6ef0e8 100644 --- a/dialect.go +++ b/dialect.go @@ -86,14 +86,12 @@ func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) } switch val.Name() { - case "NullableInt64", "NullInt64": + case "NullInt64": return "integer" - case "NullableFloat64", "NullFloat64": + case "NullFloat64": return "real" - case "NullableBool", "NullBool": + case "NullBool": return "integer" - case "NullableBytes": - return "blob" case "Time": return "datetime" } @@ -171,7 +169,9 @@ func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr boo return "bigserial" } return "bigint" - case reflect.Float64, reflect.Float32: + case reflect.Float64: + return "double precision" + case reflect.Float32: return "real" case reflect.Slice: if val.Elem().Kind() == reflect.Uint8 { @@ -180,15 +180,13 @@ func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr boo } switch val.Name() { - case "NullableInt64", "NullInt64": + case "NullInt64": return "bigint" - case "NullableFloat64", "NullFloat64": - return "real" - case "NullableBool", "NullBool": - return "smallint" - case "NullableBytes": - return "bytea" - case "Time", "NullTime": + case "NullFloat64": + return "double precision" + case "NullBool": + return "boolean" + case "Time": return "timestamp with time zone" } @@ -248,7 +246,7 @@ func (d PostgresDialect) QuoteField(f string) string { } func (d PostgresDialect) QuotedTableForQuery(schema string, table string) string { - if (strings.TrimSpace(schema) == "") { + if strings.TrimSpace(schema) == "" { return d.QuoteField(table) } @@ -300,14 +298,12 @@ func (m MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) } switch val.Name() { - case "NullableInt64", "NullInt64": + case "NullInt64": return "bigint" - case "NullableFloat64", "NullFloat64": + case "NullFloat64": return "double" - case "NullableBool", "NullBool": + case "NullBool": return "tinyint" - case "NullableBytes": - return "mediumblob" case "Time": return "datetime" }