Skip to content

Commit

Permalink
Remove many to many TX condition for EagerPreload (#645)
Browse files Browse the repository at this point in the history
* Remove the need to use Tx when loading many to many associations

* replace TX access to create a new tx.Store.Transaction() object
  • Loading branch information
larrymjordan committed May 6, 2021
1 parent 96f8e48 commit aeb9b56
Showing 1 changed file with 55 additions and 50 deletions.
105 changes: 55 additions & 50 deletions preload_associations.go
Expand Up @@ -437,72 +437,77 @@ func preloadManyToMany(tx *Connection, asoc *AssociationMetaInfo, mmi *ModelMeta
manyToManyTableName = strings.TrimSpace(manyToManyTableName[:strings.Index(manyToManyTableName, ":")])
}

if tx.TX != nil {
sql := fmt.Sprintf("SELECT %s, %s FROM %s WHERE %s in (?)", modelAssociationName, assocFkName, manyToManyTableName, modelAssociationName)
sql, args, _ := sqlx.In(sql, ids)
sql = tx.Dialect.TranslateSQL(sql)
log(logging.SQL, sql, args...)
rows, err := tx.TX.Queryx(sql, args...)
sql := fmt.Sprintf("SELECT %s, %s FROM %s WHERE %s in (?)", modelAssociationName, assocFkName, manyToManyTableName, modelAssociationName)
sql, args, _ := sqlx.In(sql, ids)
sql = tx.Dialect.TranslateSQL(sql)
log(logging.SQL, sql, args...)

cn, err := tx.Store.Transaction()
if err != nil {
return err
}

rows, err := cn.Queryx(sql, args...)
if err != nil {
return err
}

mapAssoc := map[string][]interface{}{}
fkids := []interface{}{}
for rows.Next() {
row, err := rows.SliceScan()
if err != nil {
return err
}

mapAssoc := map[string][]interface{}{}
fkids := []interface{}{}
for rows.Next() {
row, err := rows.SliceScan()
if err != nil {
return err
if len(row) > 0 {
if _, ok := row[0].([]uint8); ok { // -> it's UUID
row[0] = string(row[0].([]uint8))
}
if len(row) > 0 {
if _, ok := row[0].([]uint8); ok { // -> it's UUID
row[0] = string(row[0].([]uint8))
}
if _, ok := row[1].([]uint8); ok { // -> it's UUID
row[1] = string(row[1].([]uint8))
}
key := fmt.Sprintf("%v", row[0])
mapAssoc[key] = append(mapAssoc[key], row[1])
fkids = append(fkids, row[1])
if _, ok := row[1].([]uint8); ok { // -> it's UUID
row[1] = string(row[1].([]uint8))
}
key := fmt.Sprintf("%v", row[0])
mapAssoc[key] = append(mapAssoc[key], row[1])
fkids = append(fkids, row[1])
}
}

q := tx.Q()
q.eager = false
q.eagerFields = []string{}
q := tx.Q()
q.eager = false
q.eagerFields = []string{}

if strings.TrimSpace(asoc.Field.Tag.Get("order_by")) != "" {
q.Order(asoc.Field.Tag.Get("order_by"))
}
if strings.TrimSpace(asoc.Field.Tag.Get("order_by")) != "" {
q.Order(asoc.Field.Tag.Get("order_by"))
}

slice := asoc.toSlice()
q.Where("id in (?)", fkids).All(slice.Interface())
slice := asoc.toSlice()
q.Where("id in (?)", fkids).All(slice.Interface())

// 2.2) load all nested associations from this assoc.
if asocNestedFields, ok := mmi.nestedFields[asoc.Path]; ok {
for _, asocNestedField := range asocNestedFields {
if err := preload(tx, slice.Interface(), asocNestedField); err != nil {
return err
}
// 2.2) load all nested associations from this assoc.
if asocNestedFields, ok := mmi.nestedFields[asoc.Path]; ok {
for _, asocNestedField := range asocNestedFields {
if err := preload(tx, slice.Interface(), asocNestedField); err != nil {
return err
}
}
}

// 3) iterate over every model and fill it with the assoc.
mmi.iterate(func(mvalue reflect.Value) {
id := mmi.mapper.FieldByName(mvalue, "ID").Interface()
if assocFkIds, ok := mapAssoc[fmt.Sprintf("%v", id)]; ok {
modelAssociationField := mmi.mapper.FieldByName(mvalue, asoc.Name)
for i := 0; i < slice.Elem().Len(); i++ {
asocValue := slice.Elem().Index(i)
for _, fkid := range assocFkIds {
if fmt.Sprintf("%v", fkid) == fmt.Sprintf("%v", mmi.mapper.FieldByName(asocValue, "ID").Interface()) {
modelAssociationField.Set(reflect.Append(modelAssociationField, asocValue))
}
// 3) iterate over every model and fill it with the assoc.
mmi.iterate(func(mvalue reflect.Value) {
id := mmi.mapper.FieldByName(mvalue, "ID").Interface()
if assocFkIds, ok := mapAssoc[fmt.Sprintf("%v", id)]; ok {
modelAssociationField := mmi.mapper.FieldByName(mvalue, asoc.Name)
for i := 0; i < slice.Elem().Len(); i++ {
asocValue := slice.Elem().Index(i)
for _, fkid := range assocFkIds {
if fmt.Sprintf("%v", fkid) == fmt.Sprintf("%v", mmi.mapper.FieldByName(asocValue, "ID").Interface()) {
modelAssociationField.Set(reflect.Append(modelAssociationField, asocValue))
}
}
}
})
}
}
})

return nil
}

Expand Down

0 comments on commit aeb9b56

Please sign in to comment.