Skip to content

Commit

Permalink
Support loading association using Join query (#302)
Browse files Browse the repository at this point in the history
* Add join assoc query builder

* support loading assoc using join

* fix select alias
  • Loading branch information
Fs02 committed Jul 2, 2022
1 parent 57e2c90 commit dfc48ca
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
31 changes: 28 additions & 3 deletions join_query.go
Expand Up @@ -20,15 +20,40 @@ func (jq JoinQuery) Build(query *Query) {
}
}

func (jq *JoinQuery) Populate(docMeta DocumentMeta) {
func (jq *JoinQuery) Populate(query *Query, docMeta DocumentMeta) {
var (
assocMeta = docMeta.Association(jq.Assoc)
assocDocMeta = assocMeta.DocumentMeta()
)

jq.Table = assocDocMeta.Table()
jq.To = jq.Table + "." + assocMeta.ForeignField()
jq.Table = assocDocMeta.Table() + " as " + jq.Assoc
jq.To = jq.Assoc + "." + assocMeta.ForeignField()
jq.From = docMeta.Table() + "." + assocMeta.ReferenceField()

// load association if defined and supported
if assocMeta.Type() == HasOne || assocMeta.Type() == BelongsTo {
var (
load = false
selectField = jq.Assoc + ".*"
)

for i := range query.SelectQuery.Fields {
if load && i > 0 {
query.SelectQuery.Fields[i-1] = query.SelectQuery.Fields[i]
}
if query.SelectQuery.Fields[i] == selectField {
load = true
}
}

if load {
fields := make([]string, len(assocDocMeta.Fields()))
for i, f := range assocDocMeta.Fields() {
fields[i] = jq.Assoc + "." + f + " as " + jq.Assoc + "." + f
}
query.SelectQuery.Fields = append(query.SelectQuery.Fields[:(len(query.SelectQuery.Fields)-1)], fields...)
}
}
}

// NewJoinWith query with custom join mode, table, field and additional filters with AND condition.
Expand Down
45 changes: 30 additions & 15 deletions join_query_test.go
Expand Up @@ -73,34 +73,49 @@ func TestJoin(t *testing.T) {

func TestJoinAssoc_hasOne(t *testing.T) {
var (
populated = rel.Build("", rel.NewJoinAssoc("address")).
Populate(rel.NewDocument(&rel.User{}, false).Meta()).
JoinQuery[0]
populated = rel.Build("", rel.Select("*", "address.*"), rel.NewJoinAssoc("address")).
Populate(rel.NewDocument(&rel.User{}, false).Meta())
)

assert.Equal(t, rel.JoinQuery{
Mode: "JOIN",
Table: "user_addresses",
To: "user_addresses.user_id",
Table: "user_addresses as address",
To: "address.user_id",
From: "users.id",
Assoc: "address",
}, populated)
}, populated.JoinQuery[0])
assert.Equal(t, []string{
"*",
"address.id as address.id",
"address.user_id as address.user_id",
"address.street as address.street",
"address.notes as address.notes",
"address.deleted_at as address.deleted_at",
}, populated.SelectQuery.Fields)
}

func TestJoinPopulate_hasOnePtr(t *testing.T) {
var (
populated = rel.Build("", rel.NewJoinAssoc("work_address")).
Populate(rel.NewDocument(&rel.User{}, false).Meta()).
JoinQuery[0]
populated = rel.Build("", rel.Select("id", "work_address.*", "name"), rel.NewJoinAssoc("work_address")).
Populate(rel.NewDocument(&rel.User{}, false).Meta())
)

assert.Equal(t, rel.JoinQuery{
Mode: "JOIN",
Table: "user_addresses",
To: "user_addresses.user_id",
Table: "user_addresses as work_address",
To: "work_address.user_id",
From: "users.id",
Assoc: "work_address",
}, populated)
}, populated.JoinQuery[0])
assert.Equal(t, []string{
"id",
"name",
"work_address.id as work_address.id",
"work_address.user_id as work_address.user_id",
"work_address.street as work_address.street",
"work_address.notes as work_address.notes",
"work_address.deleted_at as work_address.deleted_at",
}, populated.SelectQuery.Fields)
}

func TestJoinPopulate_hasMany(t *testing.T) {
Expand All @@ -112,7 +127,7 @@ func TestJoinPopulate_hasMany(t *testing.T) {

assert.Equal(t, rel.JoinQuery{
Mode: "JOIN",
Table: "transactions",
Table: "transactions as transactions",
To: "transactions.user_id",
From: "users.id",
Assoc: "transactions",
Expand All @@ -128,8 +143,8 @@ func TestJoinAssoc_belongsTo(t *testing.T) {

assert.Equal(t, rel.JoinQuery{
Mode: "JOIN",
Table: "users",
To: "users.id",
Table: "users as user",
To: "user.id",
From: "user_addresses.user_id",
Assoc: "user",
}, populated)
Expand Down
4 changes: 2 additions & 2 deletions query.go
Expand Up @@ -11,7 +11,7 @@ type Querier interface {
}

type QueryPopulator interface {
Populate(DocumentMeta)
Populate(*Query, DocumentMeta)
}

// Build for given table using given queriers.
Expand Down Expand Up @@ -130,7 +130,7 @@ func (q Query) Build(query *Query) {

func (q Query) Populate(documentMeta DocumentMeta) Query {
for i := range q.queryPopulators {
q.queryPopulators[i].Populate(documentMeta)
q.queryPopulators[i].Populate(&q, documentMeta)
}

return q
Expand Down
2 changes: 1 addition & 1 deletion query_test.go
Expand Up @@ -383,7 +383,7 @@ func TestQuery_JoinAssoc(t *testing.T) {
JoinQuery: []rel.JoinQuery{
{
Mode: "JOIN",
Table: "transactions",
Table: "transactions as transactions",
To: "transactions.user_id",
From: "users.id",
Assoc: "transactions",
Expand Down

0 comments on commit dfc48ca

Please sign in to comment.