Skip to content

Commit

Permalink
Merge pull request #29 from twharmon/no-limit
Browse files Browse the repository at this point in the history
Remove the requirement that selects must specify limit
  • Loading branch information
twharmon authored Mar 25, 2022
2 parents 38e5de8 + 62939b3 commit 1fad099
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 42 deletions.
34 changes: 24 additions & 10 deletions select_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,13 @@ func (sq *SelectQuery) Get(out interface{}) error {
if el.Kind() != reflect.Struct {
break
}
if sq.limit == 0 {
return errors.New("limit must be set and not zero when selecting multiple rows")
}
var err error
sq.model, err = sq.db.getModelOf(el)
if err != nil {
return err
}
return sq.toMany(t, out)
case reflect.Struct:
if sq.limit == 0 {
return errors.New("limit must be set and not zero when selecting multiple rows")
}
var err error
sq.model, err = sq.db.getModelOf(el)
if err != nil {
Expand Down Expand Up @@ -215,7 +209,12 @@ func (sq *SelectQuery) toMany(sliceType reflect.Type, outs interface{}) error {
return err
}
defer rows.Close()
newOuts := reflect.MakeSlice(sliceType, int(sq.limit), int(sq.limit))
var newOuts reflect.Value
if sq.limit == 0 {
newOuts = reflect.MakeSlice(sliceType, 8, 8)
} else {
newOuts = reflect.MakeSlice(sliceType, int(sq.limit), int(sq.limit))
}
i := 0
columns, _ := rows.Columns()
fieldCount := len(columns)
Expand All @@ -228,6 +227,10 @@ func (sq *SelectQuery) toMany(sliceType reflect.Type, outs interface{}) error {
}
dests := make([]interface{}, fieldCount)
for rows.Next() {
if newOuts.Len() == i {
newOuts.SetCap(newOuts.Len() * 2)
newOuts.SetLen(newOuts.Len() * 2)
}
newOut := newOuts.Index(i)
newOut.Set(reflect.New(sq.model.typ))
for j := 0; j < fieldCount; j++ {
Expand All @@ -253,7 +256,12 @@ func (sq *SelectQuery) toManyValues(sliceType reflect.Type, outs interface{}) er
return err
}
defer rows.Close()
newOuts := reflect.MakeSlice(sliceType, int(sq.limit), int(sq.limit))
var newOuts reflect.Value
if sq.limit == 0 {
newOuts = reflect.MakeSlice(sliceType, 8, 8)
} else {
newOuts = reflect.MakeSlice(sliceType, int(sq.limit), int(sq.limit))
}
i := 0
columns, _ := rows.Columns()
fieldCount := len(columns)
Expand All @@ -267,6 +275,10 @@ func (sq *SelectQuery) toManyValues(sliceType reflect.Type, outs interface{}) er
dests := make([]interface{}, fieldCount)
newOut := newOuts.Index(0)
for rows.Next() {
if newOuts.Len() == i {
newOuts.SetCap(newOuts.Len() * 2)
newOuts.SetLen(newOuts.Len() * 2)
}
newOut = newOuts.Index(i)
for j := 0; j < fieldCount; j++ {
dests[j] = newOut.Field(fieldIndecies[j]).Addr().Interface()
Expand Down Expand Up @@ -324,8 +336,10 @@ func (sq *SelectQuery) String() string {
q.WriteString(sq.order)
}
if sq.many {
q.WriteString(" limit ")
q.WriteString(strconv.FormatInt(sq.limit, 10))
if sq.limit > 0 {
q.WriteString(" limit ")
q.WriteString(strconv.FormatInt(sq.limit, 10))
}
} else {
q.WriteString(" limit 1")
}
Expand Down
94 changes: 62 additions & 32 deletions select_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,76 @@ func TestSelectQueryMany(t *testing.T) {
for _, c := range control {
rows.AddRow(c.ID, c.Name)
}
mock.ExpectQuery(`^select \* from t limit 10$`).WillReturnRows(rows)
mock.ExpectQuery(`^select \* from t$`).WillReturnRows(rows)
var test []*T
check(t, db.Select("*").Limit(10).Get(&test))
check(t, db.Select("*").Get(&test))
check(t, mock.ExpectationsWereMet())
for i := 0; i < len(control); i++ {
equals(t, control[i], test[i])
}
}

func TestSelectQueryManyValues(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `idx:"primary"`
Name string
}
control := []T{
{
ID: 5,
Name: "foo",
},
{
ID: 6,
Name: "bar",
},
}
rows := sqlmock.NewRows([]string{"id", "name"})
for _, c := range control {
rows.AddRow(c.ID, c.Name)
}
mock.ExpectQuery(`^select \* from t$`).WillReturnRows(rows)
var test []T
check(t, db.Select("*").Get(&test))
check(t, mock.ExpectationsWereMet())
for i := 0; i < len(control); i++ {
equals(t, control[i], test[i])
}
}

func TestSelectQueryManyLimit(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
ID int `idx:"primary"`
Name string
}
control := []*T{
{
ID: 5,
Name: "foo",
},
{
ID: 6,
Name: "bar",
},
}
rows := sqlmock.NewRows([]string{"id", "name"})
for _, c := range control {
rows.AddRow(c.ID, c.Name)
}
mock.ExpectQuery(`^select \* from t$`).WillReturnRows(rows)
var test []*T
check(t, db.Select("*").Get(&test))
check(t, mock.ExpectationsWereMet())
for i := 0; i < len(control); i++ {
equals(t, control[i], test[i])
}
}

func TestSelectQueryManyValuesLimit(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
type T struct {
Expand Down Expand Up @@ -227,36 +287,6 @@ func TestSelectQueryErrNotStructOrSlice(t *testing.T) {
}
}

func TestSelectQueryErrLimitZeroManyValues(t *testing.T) {
db, _, err := getMockDB()
check(t, err)
type T struct {
ID int `idx:"primary"`
Name string
}
var test []T
if err := db.Select("*").Get(&test); err == nil {
t.Fatalf("expected err to be non nil")
} else {
contains(t, err.Error(), "limit")
}
}

func TestSelectQueryErrLimitZeroMany(t *testing.T) {
db, _, err := getMockDB()
check(t, err)
type T struct {
ID int `idx:"primary"`
Name string
}
var test []*T
if err := db.Select("*").Get(&test); err == nil {
t.Fatalf("expected err to be non nil")
} else {
contains(t, err.Error(), "limit")
}
}

func TestSelectQueryCustomColumn(t *testing.T) {
db, mock, err := getMockDB()
check(t, err)
Expand Down

0 comments on commit 1fad099

Please sign in to comment.