Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support embeddable structs #262

Merged
merged 10 commits into from
Feb 14, 2022
33 changes: 17 additions & 16 deletions association.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ const (
)

type associationKey struct {
rt reflect.Type
index int
rt reflect.Type
// string repr of index, because []int is not hashable
index string
}

type associationData struct {
typ AssociationType
targetIndex []int
referenceField string
referenceIndex int
referenceIndex []int
foreignField string
foreignIndex int
foreignIndex []int
through string
autoload bool
autosave bool
Expand Down Expand Up @@ -64,7 +65,7 @@ func (a Association) LazyDocument() (*Document, bool) {

func (a Association) document(lazy bool) (*Document, bool) {
var (
rv = a.rv.FieldByIndex(a.data.targetIndex)
rv = reflectValueFieldByIndex(a.rv, a.data.targetIndex, !lazy)
)

switch rv.Kind() {
Expand Down Expand Up @@ -95,7 +96,7 @@ func (a Association) document(lazy bool) (*Document, bool) {
// If association is zero, second return value will be false.
func (a Association) Collection() (*Collection, bool) {
var (
rv = a.rv.FieldByIndex(a.data.targetIndex)
rv = reflectValueFieldByIndex(a.rv, a.data.targetIndex, true)
loaded = !rv.IsNil()
)

Expand All @@ -118,7 +119,7 @@ func (a Association) Collection() (*Collection, bool) {
// IsZero returns true if association is not loaded.
func (a Association) IsZero() bool {
var (
rv = a.rv.FieldByIndex(a.data.targetIndex)
rv = reflectValueFieldByIndex(a.rv, a.data.targetIndex, false)
)

return isDeepZero(reflect.Indirect(rv), 1)
Expand All @@ -131,7 +132,7 @@ func (a Association) ReferenceField() string {

// ReferenceValue of the association.
func (a Association) ReferenceValue() interface{} {
return indirectInterface(a.rv.Field(a.data.referenceIndex))
return indirectInterface(reflectValueFieldByIndex(a.rv, a.data.referenceIndex, false))
}

// ForeignField of the association.
Expand All @@ -147,14 +148,14 @@ func (a Association) ForeignValue() interface{} {
}

var (
rv = a.rv.FieldByIndex(a.data.targetIndex)
rv = reflectValueFieldByIndex(a.rv, a.data.targetIndex, false)
)

if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}

return indirectInterface(rv.Field(a.data.foreignIndex))
return indirectInterface(reflectValueFieldByIndex(rv, a.data.foreignIndex, false))
}

// Through return intermediary association.
Expand All @@ -172,7 +173,7 @@ func (a Association) Autosave() bool {
return a.data.autosave
}

func newAssociation(rv reflect.Value, index int) Association {
func newAssociation(rv reflect.Value, index []int) Association {
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
Expand All @@ -183,11 +184,11 @@ func newAssociation(rv reflect.Value, index int) Association {
}
}

func extractAssociationData(rt reflect.Type, index int) associationData {
func extractAssociationData(rt reflect.Type, index []int) associationData {
var (
key = associationKey{
rt: rt,
index: index,
index: encodeIndices(index),
}
)

Expand All @@ -196,13 +197,13 @@ func extractAssociationData(rt reflect.Type, index int) associationData {
}

var (
sf = rt.Field(index)
sf = rt.FieldByIndex(index)
ft = sf.Type
ref = sf.Tag.Get("ref")
fk = sf.Tag.Get("fk")
fName = fieldName(sf)
fName, _ = fieldName(sf)
assocData = associationData{
targetIndex: sf.Index,
targetIndex: index,
through: sf.Tag.Get("through"),
autoload: sf.Tag.Get("auto") == "true" || sf.Tag.Get("autoload") == "true",
autosave: sf.Tag.Get("auto") == "true" || sf.Tag.Get("autosave") == "true",
Expand Down
38 changes: 36 additions & 2 deletions association_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestAssociation_Document(t *testing.T) {
var (
rv = reflect.ValueOf(test.data)
sf, _ = rv.Type().Elem().FieldByName(test.field)
assoc = newAssociation(rv, sf.Index[0])
assoc = newAssociation(rv, sf.Index)
doc, loaded = assoc.Document()
)

Expand Down Expand Up @@ -150,6 +150,40 @@ func TestAssociation_Document(t *testing.T) {
}
}

func TestAssociation_Embedded(t *testing.T) {
type EmbeddedID struct {
ID int
}
type Purchase struct {
EmbeddedID
}
type PurchaseInfo struct {
PurchaseID int
Purchase *Purchase
}
type Item struct {
EmbeddedID
PurchaseInfo
}

var (
purchase = &Purchase{EmbeddedID: EmbeddedID{ID: 1}}
item = &Item{EmbeddedID: EmbeddedID{ID: 1},
PurchaseInfo: PurchaseInfo{Purchase: purchase, PurchaseID: purchase.ID}}
rv = reflect.ValueOf(item)
sf, _ = rv.Type().Elem().FieldByName("Purchase")
assoc = newAssociation(rv, sf.Index)
_, loaded = assoc.Document()
)

assert.Equal(t, AssociationType(BelongsTo), assoc.Type())
assert.True(t, loaded)
assert.Equal(t, "purchase_id", assoc.ReferenceField())
assert.Equal(t, item.ID, assoc.ReferenceValue())
assert.Equal(t, "id", assoc.ForeignField())
assert.Equal(t, purchase.ID, assoc.ForeignValue())
}

func TestAssociation_Collection(t *testing.T) {
var (
transaction = &Transaction{ID: 1}
Expand Down Expand Up @@ -269,7 +303,7 @@ func TestAssociation_Collection(t *testing.T) {
var (
rv = reflect.ValueOf(test.data)
sf, _ = rv.Type().Elem().FieldByName(test.field)
assoc = newAssociation(rv, sf.Index[0])
assoc = newAssociation(rv, sf.Index)
col, loaded = assoc.Collection()
)

Expand Down
2 changes: 1 addition & 1 deletion collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (c Collection) PrimaryValues() []interface{} {

for j := 0; j < idxLen; j++ {
if item := c.rvIndex(j); item.IsValid() {
values = append(values, item.Field(index[i]).Interface())
values = append(values, reflectValueFieldByIndex(item, index[i], false).Interface())
}
}

Expand Down