Skip to content

Commit

Permalink
Merge pull request #28 from twharmon/tags
Browse files Browse the repository at this point in the history
Add test case for omitted field
  • Loading branch information
twharmon authored Mar 25, 2022
2 parents f80df0d + e28f574 commit 38e5de8
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.13.x]
go-version: [1.17.x, 1.18.x]
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ db := gosql.New(sqliteDB)

// Define a struct that includes a primary key
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Email string
IsActive bool
}
Expand Down
17 changes: 10 additions & 7 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ func (db *DB) register(typ reflect.Type) error {
m.primaryFieldIndecies = nil
for i := 0; i < m.typ.NumField(); i++ {
f := m.typ.Field(i)
tag, ok := f.Tag.Lookup("gosql")
if ok && tag == "-" {
continue
}
if ok && tag == "primary" {
if tag, ok := f.Tag.Lookup("idx"); ok && tag == "primary" {
m.primaryFieldIndecies = append(m.primaryFieldIndecies, i)
}
m.fields = append(m.fields, toSnakeCase(f.Name))
if tag, ok := f.Tag.Lookup("col"); ok {
if tag == "-" {
continue
}
m.fields = append(m.fields, tag)
} else {
m.fields = append(m.fields, toSnakeCase(f.Name))
}
}
if err := db.mustBeValid(m); err != nil {
return err
Expand Down Expand Up @@ -60,7 +63,7 @@ func (db *DB) mustBeValid(m *model) error {
return fmt.Errorf("model %s found more than once", m.name)
}
if len(m.primaryFieldIndecies) == 0 {
return fmt.Errorf("model %s must have at least one field tagged `gosql:\"primary\"`", m.name)
return fmt.Errorf("model %s must have at least one field tagged `idx:\"primary\"`", m.name)
}
return nil
}
Expand Down
53 changes: 34 additions & 19 deletions db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestDelete(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
}
deleteModel := T{5}
mock.ExpectExec(`^delete from t where id = \?$`).WithArgs(deleteModel.ID).WillReturnResult(sqlmock.NewResult(0, 1))
Expand All @@ -28,7 +28,7 @@ func TestUpdate(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
updateModel := T{5, "foo"}
Expand All @@ -42,7 +42,7 @@ func TestUpdateThreeFields(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
Email string
}
Expand All @@ -57,9 +57,9 @@ func TestUpdateThreeFieldsTwoPrimaries(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
Email string `gosql:"primary"`
Email string `idx:"primary"`
}
updateModel := T{5, "foo", "[email protected]"}
mock.ExpectExec(`^update t set name = \? where id = \? and email = \?$`).WithArgs(updateModel.Name, updateModel.ID, updateModel.Email).WillReturnResult(sqlmock.NewResult(0, 1))
Expand All @@ -81,7 +81,7 @@ func TestInsert(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
insertModel := T{Name: "foo"}
Expand All @@ -95,7 +95,7 @@ func TestInsertWithPrimary(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
insertModelWithPrimary := T{5, "foo"}
Expand All @@ -109,8 +109,8 @@ func TestInsertWithAllFieldsPrimary(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
Name string `gosql:"primary"`
ID int `idx:"primary"`
Name string `idx:"primary"`
}
model := T{5, "foo"}
mock.ExpectExec(`^insert into t \(id, name\) values \(\?, \?\)$`).WithArgs(model.ID, model.Name).WillReturnResult(sqlmock.NewResult(0, 1))
Expand All @@ -123,9 +123,9 @@ func TestInsertWith1stAndLastFieldsPrimary(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Email string
Name string `gosql:"primary"`
Name string `idx:"primary"`
}
model := T{5, "", "foo"}
mock.ExpectExec(`^insert into t \(id, email, name\) values \(\?, \?, \?\)$`).WithArgs(model.ID, model.Email, model.Name).WillReturnResult(sqlmock.NewResult(0, 1))
Expand All @@ -134,13 +134,28 @@ func TestInsertWith1stAndLastFieldsPrimary(t *testing.T) {
check(t, mock.ExpectationsWereMet())
}

func TestInsertWithOmittedField(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `idx:"primary"`
Email string
Name string `col:"-"`
}
model := T{5, "", "foo"}
mock.ExpectExec(`^insert into t \(id, email\) values \(\?, \?\)$`).WithArgs(model.ID, model.Email).WillReturnResult(sqlmock.NewResult(0, 1))
_, err = db.Insert(&model)
check(t, err)
check(t, mock.ExpectationsWereMet())
}

func ExampleDB_Insert() {
os.Remove("/tmp/foo.db")
sqliteDB, _ := sql.Open("sqlite3", "/tmp/foo.db")
sqliteDB.Exec("create table user (id integer not null primary key, name text); delete from user")
db := gosql.New(sqliteDB)
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
db.Insert(&User{Name: "Gopher"})
Expand All @@ -156,7 +171,7 @@ func ExampleDB_Update() {
sqliteDB.Exec("create table user (id integer not null primary key, name text, email text); delete from user")
db := gosql.New(sqliteDB)
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
Email string
}
Expand All @@ -177,7 +192,7 @@ func ExampleDB_Delete() {
sqliteDB.Exec("create table user (id integer not null primary key, name text); delete from user")
db := gosql.New(sqliteDB)
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
user := User{ID: 5, Name: "Gopher"}
Expand All @@ -192,7 +207,7 @@ func ExampleDB_Delete() {
func BenchmarkInsert(b *testing.B) {
db := getSQLiteDB(b, "create table user (id integer not null primary key, name text); delete from user")
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
user := User{Name: "Gopher"}
Expand All @@ -206,7 +221,7 @@ func BenchmarkInsert(b *testing.B) {
func BenchmarkUpdate(b *testing.B) {
db := getSQLiteDB(b, "create table user (id integer not null primary key, name text); delete from user")
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
user := User{Name: "Gopher"}
Expand All @@ -222,7 +237,7 @@ func BenchmarkUpdate(b *testing.B) {
func BenchmarkSelect(b *testing.B) {
db := getSQLiteDB(b, "create table user (id integer not null primary key, name text); delete from user")
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
user := User{ID: 5, Name: "Gopher"}
Expand All @@ -238,7 +253,7 @@ func BenchmarkSelect(b *testing.B) {
func BenchmarkSelectMany(b *testing.B) {
db := getSQLiteDB(b, "create table user (id integer not null primary key, name text); delete from user")
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
user := User{Name: "Gopher"}
Expand All @@ -256,7 +271,7 @@ func BenchmarkSelectMany(b *testing.B) {
func BenchmarkSelectManyPtrs(b *testing.B) {
db := getSQLiteDB(b, "create table user (id integer not null primary key, name text); delete from user")
type User struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name string
}
user := User{Name: "Gopher"}
Expand Down
4 changes: 2 additions & 2 deletions null_int64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func TestNullInt64Valid(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name gosql.NullInt64
}
control := T{
Expand All @@ -31,7 +31,7 @@ func TestNullInt64NotValid(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name gosql.NullInt64
}
control := T{
Expand Down
4 changes: 2 additions & 2 deletions null_string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func TestNullStringValid(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name gosql.NullString
}
control := T{
Expand All @@ -31,7 +31,7 @@ func TestNullStringNotValid(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name gosql.NullString
}
control := T{
Expand Down
4 changes: 2 additions & 2 deletions null_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func TestNullTimeValid(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name gosql.NullTime
}
control := T{
Expand All @@ -32,7 +32,7 @@ func TestNullTimeNotValid(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `gosql:"primary"`
ID int `idx:"primary"`
Name gosql.NullTime
}
control := T{
Expand Down
12 changes: 11 additions & 1 deletion select_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ func (sq *SelectQuery) toOne(out interface{}) error {
for rows.Next() {
dests := make([]interface{}, fieldCount)
for j := 0; j < fieldCount; j++ {
dests[j] = e.Field(sq.model.getFieldIndexByName(columns[j])).Addr().Interface()
fieldIdx := sq.model.getFieldIndexByName(columns[j])
if fieldIdx < 0 {
return fmt.Errorf("no field for column %s", columns[j])
}
dests[j] = e.Field(fieldIdx).Addr().Interface()
}
if err := rows.Scan(dests...); err != nil {
return err
Expand Down Expand Up @@ -218,6 +222,9 @@ func (sq *SelectQuery) toMany(sliceType reflect.Type, outs interface{}) error {
fieldIndecies := make([]int, fieldCount)
for j := 0; j < fieldCount; j++ {
fieldIndecies[j] = sq.model.getFieldIndexByName(columns[j])
if fieldIndecies[j] < 0 {
return fmt.Errorf("no field for column %s", columns[j])
}
}
dests := make([]interface{}, fieldCount)
for rows.Next() {
Expand Down Expand Up @@ -253,6 +260,9 @@ func (sq *SelectQuery) toManyValues(sliceType reflect.Type, outs interface{}) er
fieldIndecies := make([]int, fieldCount)
for j := 0; j < fieldCount; j++ {
fieldIndecies[j] = sq.model.getFieldIndexByName(columns[j])
if fieldIndecies[j] < 0 {
return fmt.Errorf("no field for column %s", columns[j])
}
}
dests := make([]interface{}, fieldCount)
newOut := newOuts.Index(0)
Expand Down
Loading

0 comments on commit 38e5de8

Please sign in to comment.