diamond-orm/query_populate.go

166 lines
4.3 KiB
Go

package orm
import (
"fmt"
"strings"
)
const PopulateAll = "~~~ALL~~~"
func join(r *Relationship) (string, string, string) {
rtable := r.RelatedModel.TableName
field := r.Model.Fields[r.FieldName]
var fk, pk, alias string
if !r.RelatedModel.embeddedIsh && !r.Model.embeddedIsh {
alias = pascalToSnakeCase(field.Name)
fk = fmt.Sprintf("%s.%s", alias, r.RelatedModel.Fields[r.RelatedModel.IDField].ColumnName)
pk = fmt.Sprintf("%s.%s", r.Model.TableName, field.ColumnName)
alias = pascalToSnakeCase(field.Name)
} else if !r.Model.embeddedIsh {
alias = pascalToSnakeCase(r.FieldName)
sid := strings.TrimSuffix(r.JoinField(), "ID")
fk = fmt.Sprintf("%s.%s", alias, r.RelatedModel.Fields[sid].ColumnName)
pk = fmt.Sprintf("%s.%s", r.Model.TableName, r.Model.Fields[r.Model.IDField].ColumnName)
}
return alias, rtable, fmt.Sprintf("%s = %s", fk, pk)
}
func m2mJoin(r *Relationship) [][3]string {
result := make([][3]string, 0)
jt := r.JoinTable()
first := [3]string{
pascalToSnakeCase(r.FieldName),
jt,
fmt.Sprintf("%s = %s",
fmt.Sprintf("%s.%s",
jt,
r.RelatedModel.Fields[r.RelatedModel.IDField].ColumnName,
),
fmt.Sprintf("%s.%s",
r.Model.TableName,
r.Model.Fields[r.Model.IDField].ColumnName,
),
),
}
second := [3]string{
pascalToSnakeCase(r.m2mInverse.FieldName),
r.RelatedModel.TableName,
fmt.Sprintf("%s = %s",
fmt.Sprintf("%s.%s", r.RelatedModel.TableName, r.RelatedModel.Fields[r.RelatedModel.IDField].ColumnName),
fmt.Sprintf("%s.%s", jt, r.m2mInverse.JoinField()),
),
}
/*first := fmt.Sprintf("%s AS %s ON %s = %s",
jt,
fmt.Sprintf("%s.%s",
jt,
r.RelatedModel.Fields[r.RelatedModel.IDField].ColumnName,
),
fmt.Sprintf("%s.%s",
r.Model.TableName,
r.Model.Fields[r.Model.IDField].ColumnName,
),
)
second := fmt.Sprintf("%s ON %s = %s",
r.RelatedModel.TableName,
fmt.Sprintf("%s.%s", r.RelatedModel.TableName, r.RelatedModel.Fields[r.RelatedModel.IDField].ColumnName),
fmt.Sprintf("%s.%s", jt, r.m2mInverse.JoinField()),
)*/
result = append(result, first, second)
return result
}
func nestedJoin(m *Model, path string) (joins [][3]string, ree []*Relationship) {
splitPath := strings.Split(path, ".")
prevModel := m
for _, f := range splitPath {
rel, ok := m.Relationships[f]
if !ok {
break
}
var (
fk, pk string
)
if !rel.Model.embeddedIsh && !rel.RelatedModel.embeddedIsh {
pk = prevModel.Fields[rel.FieldName].ColumnName
fk = rel.RelatedModel.Fields[rel.RelatedModel.IDField].ColumnName
} else if !rel.Model.embeddedIsh {
pk = prevModel.Fields[prevModel.IDField].ColumnName
fk = rel.RelatedModel.Fields[strings.TrimSuffix(rel.JoinField(), "ID")].ColumnName
}
ree = append(ree, rel)
j2 := [3]string{
rel.Model.Fields[rel.FieldName].ColumnName,
rel.RelatedModel.TableName,
fmt.Sprintf("%s.%s = %s.%s",
rel.RelatedModel.TableName, fk,
prevModel.TableName, pk),
}
/*j2 := fmt.Sprintf("%s AS %s ON %s.%s = %s.%s",
rel.RelatedModel.TableName,
rel.Model.Fields[rel.FieldName].ColumnName,
rel.RelatedModel.TableName, fk,
prevModel.TableName, pk,
)*/
joins = append(joins, j2)
prevModel = rel.RelatedModel
}
return
}
func (q *Query) Populate(relation string) *Query {
if relation == PopulateAll {
for _, rel := range q.model.Relationships {
if rel.Type == ManyToMany {
mjs := m2mJoin(rel)
for _, ajoin := range mjs {
q.joins[rel] = [3]string{
ajoin[0],
ajoin[1],
ajoin[2],
}
}
//q.joins = append(q.joins, m2mJoin(rel)...)
} else {
alias, tn, cond := join(rel)
q.joins[rel] = [3]string{
alias,
tn,
cond,
}
//q.joins = append(q.joins, tn)
}
q.relatedModels[rel.RelatedModel.Name] = rel.RelatedModel
}
} else {
if strings.Contains(relation, ".") {
njs, rmodels := nestedJoin(q.model, relation)
for i, m := range rmodels {
curTuple := njs[i]
q.joins[m] = [3]string{
curTuple[0],
curTuple[1],
curTuple[2],
}
q.relatedModels[m.Model.Name] = m.Model
}
//q.joins = append(q.joins, njs...)
} else {
rel, ok := q.model.Relationships[relation]
if ok {
alias, tn, j := join(rel)
q.joins[rel] = [3]string{
alias,
tn,
j,
}
//q.joins = append(q.joins, tn)
q.relatedModels[rel.RelatedModel.Name] = rel.RelatedModel
}
}
}
return q
}