diff --git a/filterapply.go b/filterapply.go index 160a734..55b8008 100644 --- a/filterapply.go +++ b/filterapply.go @@ -26,6 +26,7 @@ type filterFieldApplier struct { isJoining bool leftJoin bool dbp DBProvider + filter yaormfilter.Filter } func getTableNameFromFilter(f yaormfilter.Filter) string { @@ -95,6 +96,7 @@ func (a *filterApplier) Apply() { statement: a.statement, tableName: a.tableName, dbp: a.dbp, + filter: a.filter, } applier.Apply() a.statement = applier.statement @@ -126,12 +128,23 @@ func (a *filterFieldApplier) setupFromTag() { a.dbFieldName = a.tagData[0] a.isJoining = false a.leftJoin = false + + // Set up LEFT JOIN from tag if len(a.tagData) == 4 && strings.Contains(a.tagData[1], "join") { a.isJoining = true if strings.Contains(a.tagData[1], "left") { a.leftJoin = true } } + + // Set up LEFT JOIN from filter option + if !a.leftJoin { + for _, option := range a.filter.GetSelectOptions() { + if option == yaormfilter.RequestOptions.LeftJoin { + a.leftJoin = true + } + } + } } func (a *filterFieldApplier) applyPtr() { diff --git a/model_test.go b/model_test.go index d052036..ef13f93 100644 --- a/model_test.go +++ b/model_test.go @@ -210,6 +210,67 @@ func TestGenericSelectOne_WithSubqueryload(t *testing.T) { assert.Equal(t, category2.ID, modelFound.(*testdata.Post).Category.ID) } +func TestGenericSelectOne_WithSubqueryloadLeftJoin(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) + category := &testdata.Category{Name: "category"} + saveModel(t, dbp, category) + category2 := &testdata.Category{Name: "category2"} + saveModel(t, dbp, category2) + post := &testdata.Post{Subject: "subject", CategoryID: category2.ID} + saveModel(t, dbp, post) + post2 := &testdata.Post{Subject: "subject", CategoryID: category2.ID, ParentPostID: post.ID} + saveModel(t, dbp, post2) + + // Join on a post with parent + modelFound, err := yaorm.GenericSelectOne(dbp, testdata.NewPostFilter().ChildrenPosts( + testdata.NewPostFilter().ID(yaormfilter.Gte(int64(1))).Subqueryload(), + ).ID( + yaormfilter.Equals(post.ID), + )) + if assert.Nil(t, err) { + assert.Equal(t, post.ID, modelFound.(*testdata.Post).ID) + assert.Len(t, modelFound.(*testdata.Post).ChildrenPost, 1) + assert.Equal(t, post2.ID, modelFound.(*testdata.Post).ChildrenPost[0].ID) + } + + // Join on a post without parent + modelFound, err = yaorm.GenericSelectOne(dbp, testdata.NewPostFilter().ChildrenPosts( + testdata.NewPostFilter().ID(yaormfilter.Gte(int64(1))).Subqueryload(), + ).ID( + yaormfilter.Equals(post2.ID), + )) + if assert.NotNil(t, err) { + assert.True(t, errors.IsNotFound(err)) + } + + // Left join on a post with parent + modelFound, err = yaorm.GenericSelectOne(dbp, testdata.NewPostFilter().ChildrenPosts( + testdata.NewPostFilter().Subqueryload().AddOption(yaormfilter.RequestOptions.LeftJoin), + ).ID( + yaormfilter.Equals(post.ID), + )) + if assert.Nil(t, err) { + assert.Equal(t, post.ID, modelFound.(*testdata.Post).ID) + assert.Len(t, modelFound.(*testdata.Post).ChildrenPost, 1) + assert.Equal(t, post2.ID, modelFound.(*testdata.Post).ChildrenPost[0].ID) + } + + // Left join on a post without parent + modelFound, err = yaorm.GenericSelectOne(dbp, testdata.NewPostFilter().ChildrenPosts( + testdata.NewPostFilter().Subqueryload().AddOption(yaormfilter.RequestOptions.LeftJoin), + ).ID( + yaormfilter.Equals(post2.ID), + )) + if assert.Nil(t, err) { + assert.Equal(t, post2.ID, modelFound.(*testdata.Post).ID) + assert.Len(t, modelFound.(*testdata.Post).ChildrenPost, 0) + } +} + func TestGenericSelectAll_WithJoinFilters(t *testing.T) { killDb, err := testdata.SetupTestDatabase("test") defer killDb() diff --git a/testdata/post.go b/testdata/post.go index 815ae65..6f46196 100644 --- a/testdata/post.go +++ b/testdata/post.go @@ -88,3 +88,9 @@ func (f *PostFilter) Metadata(metadata ...yaormfilter.Filter) *PostFilter { } return f } + +// AddOption adds an option on the current query +func (f *PostFilter) AddOption(opt yaormfilter.RequestOption) yaormfilter.Filter { + f.AddOption_(opt) + return f +}