Skip to content

Commit

Permalink
Support slice of filters to subqueryload
Browse files Browse the repository at this point in the history
Signed-off-by: Geoffrey Bauduin <geoffrey.bauduin@corp.ovh.com>
  • Loading branch information
geoffreybauduin committed Dec 14, 2017
1 parent 945fb6c commit 7446ab3
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 9 deletions.
43 changes: 40 additions & 3 deletions model.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,22 @@ func formatTablenameFromError(m Model) string {
return strings.Join(words, "")
}

func filterShouldSubqueryload(filterFound reflect.Value) bool {
f := filterFound.Interface()
switch f.(type) {
case yaormfilter.Filter:
return f.(yaormfilter.Filter).ShouldSubqueryload()
case []yaormfilter.Filter:
arr := f.([]yaormfilter.Filter)
for _, arrElem := range arr {
if arrElem.ShouldSubqueryload() {
return true
}
}
}
return false
}

func finishSelect(dbp DBProvider, m interface{}, f yaormfilter.Filter) error {
fkPerModel := map[string]map[interface{}][]reflect.Value{}
valueF := reflect.Indirect(reflect.ValueOf(f))
Expand All @@ -332,7 +348,7 @@ func finishSelect(dbp DBProvider, m interface{}, f yaormfilter.Filter) error {
continue
}
filterFound := valueF.Field(i)
if !filterFound.IsNil() && filterFound.Interface().(yaormfilter.Filter).ShouldSubqueryload() {
if !filterFound.IsNil() && filterShouldSubqueryload(filterFound) {
// prevent scope overriding of fkPerModel
var err error
fkPerModel, err = feedFkPerModel(m, fkPerModel, dbFieldData)
Expand All @@ -355,8 +371,8 @@ func finishSelect(dbp DBProvider, m interface{}, f yaormfilter.Filter) error {
continue
}
filterFound := valueF.Field(i)
if !filterFound.IsNil() && filterFound.Interface().(yaormfilter.Filter).ShouldSubqueryload() {
err = finishSelect(dbp, data, filterFound.Interface().(yaormfilter.Filter))
if !filterFound.IsNil() && filterShouldSubqueryload(filterFound) {
err = finishSelectFromFilter(dbp, data, filterFound.Interface())
if err != nil {
return err
}
Expand All @@ -366,6 +382,27 @@ func finishSelect(dbp DBProvider, m interface{}, f yaormfilter.Filter) error {
return nil
}

func finishSelectFromFilter(dbp DBProvider, m interface{}, f interface{}) error {
switch f.(type) {
case yaormfilter.Filter:
err := finishSelect(dbp, m, f.(yaormfilter.Filter))
if err != nil {
return err
}
return nil
case []yaormfilter.Filter:
arr := f.([]yaormfilter.Filter)
for _, arrElem := range arr {
err := finishSelect(dbp, m, arrElem)
if err != nil {
return err
}
}
return nil
}
return errors.Errorf("Could not cast filter provided to correct type")
}

func feedFkPerModel(m interface{}, fkPerModel map[string]map[interface{}][]reflect.Value, dbFieldData string) (map[string]map[interface{}][]reflect.Value, error) {
s := reflect.Indirect(reflect.ValueOf(m))
if s.Kind() == reflect.Slice {
Expand Down
18 changes: 18 additions & 0 deletions model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,21 @@ func TestSaveWithPrimaryKeys(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, "regular", postType.(*testdata.PostType).Type)
}

func TestGenericSelectOne_WithSubqueryloadSliceFilter(t *testing.T) {
killDb, err := testdata.SetupTestDatabase("test")
defer killDb()
assert.Nil(t, err)
dbp, err := yaorm.NewDBProvider(context.TODO(), "test")
assert.Nil(t, err)
post := &testdata.Post{Subject: "subject", CategoryID: 1}
saveModel(t, dbp, post)
pm := &testdata.PostMetadata{PostID: post.ID, Key: "test", Value: "foo"}
saveModel(t, dbp, pm)
modelFound, err := yaorm.GenericSelectOne(dbp, testdata.NewPostFilter().Metadata(
testdata.NewPostMetadataFilter().Subqueryload(),
testdata.NewPostMetadataFilter().Subqueryload(),
))
assert.Nil(t, err)
assert.Len(t, modelFound.(*testdata.Post).Metadata, 1)
}
29 changes: 23 additions & 6 deletions testdata/post.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package testdata

import (
"fmt"

"github.com/geoffreybauduin/yaorm"
"github.com/geoffreybauduin/yaorm/yaormfilter"
)

type Post struct {
yaorm.DatabaseModel
ID int64 `db:"id"`
Subject string `db:"subject"`
CategoryID int64 `db:"category_id"`
Category *Category `db:"-" filterload:"category,category_id"`
ParentPostID int64 `db:"parent_post_id"`
ChildrenPost []*Post `db:"-" filterload:"post,id,parent_post_id"`
ID int64 `db:"id"`
Subject string `db:"subject"`
CategoryID int64 `db:"category_id"`
Category *Category `db:"-" filterload:"category,category_id"`
ParentPostID int64 `db:"parent_post_id"`
ChildrenPost []*Post `db:"-" filterload:"post,id,parent_post_id"`
Metadata []*PostMetadata `db:"-" filterload:"post_metadata,id,post_id"`
}

type PostFilter struct {
Expand All @@ -22,6 +25,7 @@ type PostFilter struct {
FilterSubject yaormfilter.ValueFilter `filter:"subject"`
FilterCategory yaormfilter.Filter `filter:"category,join,id,category_id" filterload:"category"`
FilterChildren yaormfilter.Filter `filter:"post,join,parent_post_id,id" filterload:"post"`
FilterMetadata []yaormfilter.Filter `filter:"post_metadata,join,post_id,id" filterload:"post_metadata"`
}

func init() {
Expand Down Expand Up @@ -71,3 +75,16 @@ func (f *PostFilter) Subqueryload() yaormfilter.Filter {
f.AllowSubqueryload()
return f
}

func (f *PostFilter) Metadata(metadata ...yaormfilter.Filter) *PostFilter {
if f.FilterMetadata == nil {
f.FilterMetadata = make([]yaormfilter.Filter, 0)
}
for _, md := range metadata {
if _, ok := md.(*PostMetadataFilter); !ok {
panic(fmt.Errorf("filter %v is not a PostMetadataFilter", md))
}
f.FilterMetadata = append(f.FilterMetadata, md)
}
return f
}
50 changes: 50 additions & 0 deletions testdata/postmetadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package testdata

import (
"github.com/geoffreybauduin/yaorm"
"github.com/geoffreybauduin/yaorm/yaormfilter"
)

type PostMetadata struct {
yaorm.DatabaseModel
PostID int64 `db:"post_id"`
Key string `db:"key"`
Value string `db:"value"`
}

type PostMetadataFilter struct {
yaormfilter.ModelFilter
FilterPostID yaormfilter.ValueFilter `filter:"post_id"`
FilterKey yaormfilter.ValueFilter `filter:"key"`
}

func (pm *PostMetadata) Save() error {
return yaorm.GenericSave(pm)
}

func init() {
yaorm.NewTable("test", "post_metadata", &PostMetadata{}).WithFilter(NewPostMetadataFilter()).WithKeys([]string{"post_id", "key"}).WithAutoIncrement(false).WithSubqueryloading(
func(dbp yaorm.DBProvider, ids []interface{}) (interface{}, error) {
return yaorm.GenericSelectAll(dbp, NewPostMetadataFilter().PostID(yaormfilter.In(ids...)))
}, "post_id",
)
}

func NewPostMetadataFilter() *PostMetadataFilter {
return &PostMetadataFilter{}
}

func (f *PostMetadataFilter) PostID(v yaormfilter.ValueFilter) *PostMetadataFilter {
f.FilterPostID = v
return f
}

func (f *PostMetadataFilter) Key(v yaormfilter.ValueFilter) *PostMetadataFilter {
f.FilterKey = v
return f
}

func (f *PostMetadataFilter) Subqueryload() yaormfilter.Filter {
f.AllowSubqueryload()
return f
}

0 comments on commit 7446ab3

Please sign in to comment.