Skip to content

Commit

Permalink
Disable "automagic" mapping of tablemap.Version
Browse files Browse the repository at this point in the history
Adding a table from a struct containing a member with name "Version" and type other than int results in a panic:
2015/01/27 15:42:57 http: panic serving 127.0.0.1:60027: reflect: call of reflect.Value.Int on string Value
goroutine 23 [running]:
net/http.func·011()
        c:/go/src/pkg/net/http/server.go:1100 +0xbe
runtime.panic(0x7059e0, 0xc082007420)
        c:/go/src/pkg/runtime/panic.c:248 +0x1d3
reflect.Value.Int(0x697be0, 0xc082016ca0, 0x0, 0x186, 0x77e3d0)
        c:/go/src/pkg/reflect/value.go:1053 +0xc3
github.com/coopernurse/gorp.bindPlan.createBindInstance(0xc08205ef00, 0x162, 0xc08201e400, 0x12, 0x20, 0x0, 0x0, 0x0, 0x77e3d0, 0x7, ...)
        C:/Users/Christian/Google Drive/Development/go/src/github.com/coopernurse/gorp/gorp.go:289 +0x177
github.com/coopernurse/gorp.(*TableMap).bindInsert(0xc082020b40, 0x761280, 0xc082016c60, 0x0, 0x196, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        C:/Users/Christian/Google Drive/Development/go/src/github.com/coopernurse/gorp/gorp.go:394 +0x6e0
github.com/coopernurse/gorp.insert(0xc0820104e0, 0x181da0, 0xc0820104e0, 0x3a3a38, 0x1, 0x1, 0x0, 0x0)
        C:/Users/Christian/Google Drive/Development/go/src/github.com/coopernurse/gorp/gorp.go:1913 +0x2dc
github.com/coopernurse/gorp.(*DbMap).Insert(0xc0820104e0, 0x3a3a38, 0x1, 0x1, 0x0, 0x0)
        C:/Users/Christian/Google Drive/Development/go/src/github.com/coopernurse/gorp/gorp.go:955 +0x97

From my POV, this is convention over configuration, just the wrong way around.

My proposed solution is to disable setting the version ColMap in AddTable(i interface{}), forcing the developer to manually set the version column name by using SetVersionCol(). This is a crude fix, but it shows the problem and how to solve it.

Update gorp_test.go

Fixed tests by using SetVersionCol on person tablemap

Remove maintainers notice (since PR is closed).  Add google group and
irc channel to Help/Support section

Use #gorp as channel

Add gopkg.in versioned releases information.

Also made the markdown headings consistently use prefixed #'s, no suffix.

Change coopernurse/gorp to go-gorp/gorp in Makefile, godoc and comments.

Extended the Exec functionality so that it can be used with named parameters.

Unexport the Executor

Removed version column detection in readStructColumns

Update gorp.go

Added warning telling users that automatic mapping of Version struct members to version column in database (optimistic locking) will be removed in V2

Update gorp.go

Changed log output to stderr

Added migration guide and notes

Added migration guide and notes about change in behaviour in Optimistic locking.

Update README.md

Update gorp.go

Corrected vim gone wild
  • Loading branch information
sqdk authored and Christian Probst committed Feb 26, 2015
1 parent 0a7ddd4 commit 04b2c71
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 74 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include $(GOROOT)/src/Make.inc

TARG = github.com/coopernurse/gorp
TARG = github.com/go-gorp/gorp
GOFILES = gorp.go dialect.go

include $(GOROOT)/src/Make.pkg
122 changes: 64 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
# Go Relational Persistence #
# Go Relational Persistence

[![build status](https://secure.travis-ci.org/go-gorp/gorp.png)](http://travis-ci.org/go-gorp/gorp)

## Call for Maintainers

Dec 7 2014

I've been slacking on keeping up with issues and PRs. I know there are
many of you out there who have active forks and some good ideas on how to
push the project forward. If you'd like to step up and either be added as
a committer to this repo, or would like to become the new canonical fork
of the project, please comment on #211 here:

https://github.com/go-gorp/gorp/issues/211

Thank you!


----

I hesitate to call gorp an ORM. Go doesn't really have objects, at least
not in the classic Smalltalk/Java sense. There goes the "O". gorp doesn't
know anything about the relationships between your structs (at least not
yet). So the "R" is questionable too (but I use it in the name because,
I hesitate to call gorp an ORM. Go doesn't really have objects, at least
not in the classic Smalltalk/Java sense. There goes the "O". gorp doesn't
know anything about the relationships between your structs (at least not
yet). So the "R" is questionable too (but I use it in the name because,
well, it seemed more clever).

The "M" is alive and well. Given some Go structs and a database, gorp
should remove a fair amount of boilerplate busy-work from your code.

I hope that gorp saves you time, minimizes the drudgery of getting data
in and out of your database, and helps your code focus on algorithms,
I hope that gorp saves you time, minimizes the drudgery of getting data
in and out of your database, and helps your code focus on algorithms,
not infrastructure.

* Bind struct fields to table columns via API or tag
Expand All @@ -47,21 +30,33 @@ not infrastructure.
* Use positional or named bind parameters in custom SELECT queries
* Optional optimistic locking using a version column (for update/deletes)

## Installation ##
## Installation

# install the library:
go get github.com/go-gorp/gorp
go get gopkg.in/gorp.v1

// use in your .go code:
import (
"github.com/go-gorp/gorp"
"gopkg.in/gorp.v1"
)

## API Documentation ##
## Versioning

This project provides a stable release (v1.x tags) and a bleeding edge codebase (master).

`gopkg.in/gorp.v1` points to the latest v1.x tag. The API's for v1 are stable and shouldn't change. Development takes place at the master branch. Althought the code in master should always compile and test successfully, it might break API's. We aim to maintain backwards compatibility, but API's and behaviour might be changed to fix a bug. Also note that API's that are new in the master branch can change until released as v2.

Full godoc output from the latest code in master is available here:
If you want to use bleeding edge, use `github.com/go-gorp/gorp` as import path.

http://godoc.org/github.com/go-gorp/gorp
## API Documentation

Full godoc output from the latest v1 release is available here:

https://godoc.org/gopkg.in/gorp.v1

For the latest code in master:

https://godoc.org/github.com/go-gorp/gorp

## Quickstart

Expand All @@ -70,7 +65,7 @@ package main

import (
"database/sql"
"github.com/go-gorp/gorp"
"gopkg.in/gorp.v1"
_ "github.com/mattn/go-sqlite3"
"log"
"time"
Expand Down Expand Up @@ -183,9 +178,9 @@ func checkErr(err error, msg string) {
}
```

## Examples ##
## Examples

### Mapping structs to tables ###
### Mapping structs to tables

First define some types:

Expand Down Expand Up @@ -248,7 +243,7 @@ t2 := dbmap.AddTableWithName(Person{}, "person_test").SetKeys(true, "Id")
t3 := dbmap.AddTableWithName(Product{}, "product_test").SetKeys(true, "Id")
```

### Struct Embedding ###
### Struct Embedding

gorp supports embedding structs. For example:

Expand Down Expand Up @@ -287,7 +282,7 @@ dbmap.CreateTablesIfNotExists()
dbmap.DropTables()
```

### SQL Logging ###
### SQL Logging

Optionally you can pass in a logger to trace all SQL statements.
I recommend enabling this initially while you're getting the feel for what
Expand All @@ -306,7 +301,7 @@ dbmap.TraceOn("[gorp]", log.New(os.Stdout, "myapp:", log.Lmicroseconds))
dbmap.TraceOff()
```

### Insert ###
### Insert

```go
// Must declare as pointers so optional callback hooks
Expand All @@ -322,7 +317,7 @@ err := dbmap.Insert(inv1, inv2)
fmt.Printf("inv1.Id=%d inv2.Id=%d\n", inv1.Id, inv2.Id)
```

### Update ###
### Update

Continuing the above example, use the `Update` method to modify an Invoice:

Expand All @@ -331,7 +326,7 @@ Continuing the above example, use the `Update` method to modify an Invoice:
count, err := dbmap.Update(inv1)
```

### Delete ###
### Delete

If you have primary key(s) defined for a struct, you can use the `Delete`
method to remove rows:
Expand All @@ -340,7 +335,7 @@ method to remove rows:
count, err := dbmap.Delete(inv1)
```

### Select by Key ###
### Select by Key

Use the `Get` method to fetch a single row by primary key. It returns
nil if no row is found.
Expand All @@ -351,9 +346,9 @@ obj, err := dbmap.Get(Invoice{}, 99)
inv := obj.(*Invoice)
```

### Ad Hoc SQL ###
### Ad Hoc SQL

#### SELECT ####
#### SELECT

`Select()` and `SelectOne()` provide a simple way to bind arbitrary queries to a slice
or a single struct.
Expand Down Expand Up @@ -413,7 +408,7 @@ if reflect.DeepEqual(list[0], expected) {
}
```

#### SELECT string or int64 ####
#### SELECT string or int64

gorp provides a few convenience methods for selecting a single string or int64.

Expand All @@ -426,7 +421,7 @@ s, err := dbmap.SelectStr("select name from foo where blah=?", blahVal)

```

#### Named bind parameters ####
#### Named bind parameters

You may use a map or struct to bind parameters by name. This is currently
only supported in SELECT queries.
Expand All @@ -438,15 +433,15 @@ _, err := dbm.Select(&dest, "select * from Foo where name = :name and age = :age
})
```

#### UPDATE / DELETE ####
#### UPDATE / DELETE

You can execute raw SQL if you wish. Particularly good for batch operations.

```go
res, err := dbmap.Exec("delete from invoice_test where PersonId=?", 10)
```

### Transactions ###
### Transactions

You can batch operations into a transaction:

Expand All @@ -467,7 +462,7 @@ func InsertInv(dbmap *DbMap, inv *Invoice, per *Person) error {
}
```

### Hooks ###
### Hooks

Use hooks to update data before/after saving to the db. Good for timestamps:

Expand Down Expand Up @@ -512,7 +507,9 @@ Full list of hooks that you can implement:

func (p *MyStruct) PostUpdate(s gorp.SqlExecutor) error

### Optimistic Locking ###
### Optimistic Locking

#### Note that this behaviour has changed in v2. See [Migration Guide](#migration-guide).

gorp provides a simple optimistic locking feature, similar to Java's JPA, that
will raise an error if you try to update/delete a row whose `version` column
Expand Down Expand Up @@ -565,7 +562,7 @@ if ok {
}
```

## Database Drivers ##
## Database Drivers

gorp uses the Go 1 `database/sql` package. A full list of compliant drivers is available here:

Expand All @@ -590,9 +587,9 @@ Note that these databases are not covered by CI and I (@coopernurse) have no goo
test them locally. So please try them and send patches as needed, but expect a bit more
unpredicability.

## Known Issues ##
## Known Issues

### SQL placeholder portability ###
### SQL placeholder portability

Different databases use different strings to indicate variable placeholders in
prepared SQL statements. Unlike some database abstraction layers (such as JDBC),
Expand All @@ -617,7 +614,7 @@ err := dbmap.SelectOne(&val, "select * from foo where id = :id",
map[string]interface{} { "id": 30})
```

### time.Time and time zones ###
### time.Time and time zones

gorp will pass `time.Time` fields through to the `database/sql` driver, but note that
the behavior of this type varies across database drivers.
Expand All @@ -627,7 +624,7 @@ MySQL users should be especially cautious. See: https://github.com/ziutek/mymys
To avoid any potential issues with timezone/DST, consider using an integer field for time
data and storing UNIX time.

## Running the tests ##
## Running the tests

The included tests may be run against MySQL, Postgresql, or sqlite3.
You must set two environment variables so the test code knows which driver to
Expand All @@ -649,19 +646,28 @@ Valid `GORP_TEST_DIALECT` values are: "mysql", "postgres", "sqlite3"
See the `test_all.sh` script for examples of all 3 databases. This is the script I run
locally to test the library.

## Performance ##
## Performance

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.

## Migration guide
#### Pre-v2 to v2
Automatic mapping of the version column used in optimistic locking has been removed as it could cause problems if the type was not int. The version column must now explicitly be set with tablemap.SetVersionCol().

## Help/Support

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.
IRC: #gorp
Mailing list: gorp-dev@googlegroups.com
Bugs/Enhancements: Create a github issue

## 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.
* Fork the `master` branch and issue pull requests targeting the `master` branch
* 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.
discuss on a GitHub issue for a while.

Thanks!

Expand Down
Loading

0 comments on commit 04b2c71

Please sign in to comment.