Skip to content

Commit

Permalink
Polish
Browse files Browse the repository at this point in the history
  • Loading branch information
islamaliev committed Jun 3, 2024
1 parent a50974a commit 9d44040
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 115 deletions.
4 changes: 2 additions & 2 deletions internal/planner/mapper/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ type Select struct {
// Selects.
Fields []Requestable

// SkipResolve is a flag that indicates that the fields in this select should not be resolved.
// It is used avoid resolving related objects if they are used in a filter and not requested in a response.
// SkipResolve is a flag that indicates that the fields in this Select don't need to be resolved.
// It is used to avoid resolving related objects if they are used only in a filter and not requested in a response.
SkipResolve bool
}

Expand Down
4 changes: 2 additions & 2 deletions internal/planner/planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,8 @@ func (p *Planner) tryOptimizeJoinDirection(node *invertibleTypeJoin, parentPlan
for subFieldName, subFieldInd := range filteredSubFields {
indexes := desc.GetIndexesOnField(subFieldName)
if len(indexes) > 0 && !filter.IsComplex(parentPlan.selectNode.filter) {
subInd := node.documentMapping.FirstIndexOfName(node.getSubTypeName())
relatedField := mapper.Field{Name: node.getSubTypeName(), Index: subInd}
subInd := node.documentMapping.FirstIndexOfName(node.parentSide.relFieldDef.Name)
relatedField := mapper.Field{Name: node.parentSide.relFieldDef.Name, Index: subInd}
fieldFilter := filter.UnwrapRelation(filter.CopyField(
parentPlan.selectNode.filter,
relatedField,
Expand Down
199 changes: 88 additions & 111 deletions internal/planner/type_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ func (n *typeIndexJoin) simpleExplain() (map[string]any, error) {

addExplainData := func(j *invertibleTypeJoin) error {
// Add the attribute(s).
simpleExplainMap[joinRootLabel] = immutable.Some(j.getRootTypeName())
simpleExplainMap[joinSubTypeNameLabel] = j.getSubTypeName()
simpleExplainMap[joinRootLabel] = immutable.Some(j.childSide.relFieldDef.Name)
simpleExplainMap[joinSubTypeNameLabel] = j.parentSide.relFieldDef.Name

subTypeExplainGraph, err := buildSimpleExplainGraph(j.childSide.plan)
if err != nil {
Expand Down Expand Up @@ -344,7 +344,6 @@ func (p *Planner) newInvertableTypeJoin(
relFieldDef: parentsRelFieldDef,
relFieldMapIndex: immutable.Some(subSelect.Index),
col: parent.collection,
requestedFields: getRequestedFields(sourcePlan),
isFirst: true,
isParent: true,
}
Expand All @@ -355,12 +354,11 @@ func (p *Planner) newInvertableTypeJoin(
}

childSide := joinSide{
plan: subSelectPlan,
relFieldDef: childsRelFieldDef,
col: subCol,
requestedFields: getRequestedFields(subSelectPlan),
isFirst: false,
isParent: false,
plan: subSelectPlan,
relFieldDef: childsRelFieldDef,
col: subCol,
isFirst: false,
isParent: false,
}

ind = subSelectPlan.DocumentMap().IndexesByName[childsRelFieldDef.Name+request.RelatedObjectID]
Expand All @@ -369,33 +367,19 @@ func (p *Planner) newInvertableTypeJoin(
}

return invertibleTypeJoin{
docMapper: docMapper{parent.documentMapping},
parentSide: parentSide,
childSide: childSide,
childSelect: subSelect,
skipChild: skipChild,
docMapper: docMapper{parent.documentMapping},
parentSide: parentSide,
childSide: childSide,
skipChild: skipChild,
}, nil
}

func getRequestedFields(sourcePlan planNode) []string {
scan := getScanNode(sourcePlan)
if scan == nil {
return nil
}
fields := make([]string, len(scan.fields))
for i := range scan.fields {
fields[i] = scan.fields[i].Name
}
return fields
}

type joinSide struct {
plan planNode
relFieldDef client.FieldDefinition
relFieldMapIndex immutable.Option[int]
relIDFieldMapIndex immutable.Option[int]
col client.Collection
requestedFields []string
isFirst bool
isParent bool
}
Expand Down Expand Up @@ -436,12 +420,14 @@ func (n *typeJoinMany) Kind() string {
return "typeJoinMany"
}

// getForeignKey returns the docID of the related object referenced by the given relation field.
func getForeignKey(node planNode, relFieldName string) string {
ind := node.DocumentMap().FirstIndexOfName(relFieldName + request.RelatedObjectID)
docIDStr, _ := node.Value().Fields[ind].(string)
return docIDStr
}

// fetchDocWithID fetches a document with the given docID from the given planNode.
func fetchDocWithID(node planNode, docID string) (bool, error) {
scan := getScanNode(node)
if scan == nil {
Expand Down Expand Up @@ -469,8 +455,7 @@ func fetchDocWithID(node planNode, docID string) (bool, error) {
type invertibleTypeJoin struct {
docMapper

childSelect *mapper.Select
skipChild bool
skipChild bool

parentSide joinSide
childSide joinSide
Expand All @@ -482,16 +467,7 @@ type invertibleTypeJoin struct {
encounteredDocIDs []string
}

func (join *invertibleTypeJoin) getRootTypeName() string {
return join.getSecondSide().relFieldDef.Name
}

func (join *invertibleTypeJoin) getSubTypeName() string {
return join.getFirstSide().relFieldDef.Name
}

func (join *invertibleTypeJoin) replaceRoot(node planNode) {
join.parentSide.plan = node
join.getFirstSide().plan = node
}

Expand Down Expand Up @@ -523,12 +499,7 @@ func (join *invertibleTypeJoin) Spans(spans core.Spans) {

func (join *invertibleTypeJoin) Source() planNode { return join.parentSide.plan }

func (join *invertibleTypeJoin) invert() {
join.childSide.isFirst = join.parentSide.isFirst
join.parentSide.isFirst = !join.parentSide.isFirst
}

type docsJoiner struct {
type primaryObjectsFetcher struct {
relIDFieldDef client.FieldDefinition
primarySide *joinSide
secondarySide *joinSide
Expand All @@ -539,17 +510,17 @@ type docsJoiner struct {
resultSecondaryDoc core.Doc
}

func newSecondaryDocsJoiner(
func newPrimaryObjectsFetcher(
primarySide, secondarySide *joinSide,
) docsJoiner {
j := docsJoiner{
) primaryObjectsFetcher {
j := primaryObjectsFetcher{
primarySide: primarySide,
secondarySide: secondarySide,
}
return j
}

func (j *docsJoiner) fetchPrimaryDocsReferencingSecondaryDoc() error {
func (j *primaryObjectsFetcher) fetchPrimaryDocsReferencingSecondaryDoc() error {
relIDFieldDef, ok := j.primarySide.col.Definition().GetFieldByName(
j.primarySide.relFieldDef.Name + request.RelatedObjectID)
if !ok {
Expand All @@ -571,7 +542,7 @@ func (j *docsJoiner) fetchPrimaryDocsReferencingSecondaryDoc() error {
return nil
}

func (j *docsJoiner) addIDFieldToScanner() {
func (j *primaryObjectsFetcher) addIDFieldToScanner() {
found := false
for i := range j.primaryScan.fields {
if j.primaryScan.fields[i].Name == j.relIDFieldDef.Name {
Expand All @@ -584,7 +555,7 @@ func (j *docsJoiner) addIDFieldToScanner() {
}
}

func (j *docsJoiner) collectDocs(numDocs int) ([]core.Doc, error) {
func (j *primaryObjectsFetcher) collectDocs(numDocs int) ([]core.Doc, error) {
p := j.primarySide.plan
if err := p.Init(); err != nil {
return nil, NewErrSubTypeInit(err)
Expand All @@ -609,15 +580,13 @@ func (j *docsJoiner) collectDocs(numDocs int) ([]core.Doc, error) {
return docs, nil
}

func (j *docsJoiner) fetchPrimaryDocs() ([]core.Doc, error) {
func (j *primaryObjectsFetcher) fetchPrimaryDocs() ([]core.Doc, error) {
j.addIDFieldToScanner()

secondaryDoc := j.secondarySide.plan.Value()
addFilterOnIDField(j.primaryScan, j.primarySide.relIDFieldMapIndex.Value(), secondaryDoc.GetID())

oldFetcher := j.primaryScan.fetcher
// TODO: check if spans are necessary to be saved
oldSpans := j.primaryScan.spans

indexOnRelation := findIndexByFieldName(j.primaryScan.col, j.relIDFieldDef.Name)
j.primaryScan.initFetcher(immutable.None[string](), indexOnRelation)
Expand All @@ -626,7 +595,6 @@ func (j *docsJoiner) fetchPrimaryDocs() ([]core.Doc, error) {

j.primaryScan.fetcher.Close()

j.primaryScan.spans = oldSpans
j.primaryScan.fetcher = oldFetcher

if err != nil {
Expand Down Expand Up @@ -679,7 +647,7 @@ func joinPrimaryDocs(primaryDocs []core.Doc, secondarySide, primarySide *joinSid
}

func (join *invertibleTypeJoin) fetchPrimaryDocsReferencingSecondaryDoc() ([]core.Doc, core.Doc, error) {
secJoiner := newSecondaryDocsJoiner(join.getPrimarySide(), join.getSecondarySide())
secJoiner := newPrimaryObjectsFetcher(join.getPrimarySide(), join.getSecondarySide())
err := secJoiner.fetchPrimaryDocsReferencingSecondaryDoc()
return secJoiner.resultPrimaryDocs, secJoiner.resultSecondaryDoc, err
}
Expand All @@ -703,75 +671,83 @@ func (join *invertibleTypeJoin) Next() (bool, error) {
return false, err
}

secondSide := join.getSecondSide()

if firstSide.isPrimary() {
secondaryDocID := getForeignKey(firstSide.plan, firstSide.relFieldDef.Name)
// TODO: add some tests with filter on nil relation
if secondaryDocID == "" {
if firstSide.isParent {
join.docsToYield = append(join.docsToYield, firstSide.plan.Value())
return true, nil
}
return join.Next()
return join.nextJoinedSecondaryDoc()
} else {
primaryDocs, secondaryDoc, err := join.fetchPrimaryDocsReferencingSecondaryDoc()
if err != nil {
return false, err
}

if !firstSide.isParent {
for i := range join.encounteredDocIDs {
if join.encounteredDocIDs[i] == secondaryDocID {
return join.Next()
}
}
join.encounteredDocIDs = append(join.encounteredDocIDs, secondaryDocID)
if join.parentSide.isPrimary() {
join.docsToYield = append(join.docsToYield, primaryDocs...)
} else {
join.docsToYield = append(join.docsToYield, secondaryDoc)
}
}

// check if there can ever be false (a.k.a. hasDoc = false)
hasDoc, err := fetchDocWithID(secondSide.plan, secondaryDocID)
if err != nil {
return false, err
return true, nil
}

func (join *invertibleTypeJoin) nextJoinedSecondaryDoc() (bool, error) {
firstSide := join.getFirstSide()
secondSide := join.getSecondSide()

secondaryDocID := getForeignKey(firstSide.plan, firstSide.relFieldDef.Name)
// TODO: add some tests with filter on nil relation
if secondaryDocID == "" {
if firstSide.isParent {
join.docsToYield = append(join.docsToYield, firstSide.plan.Value())
return true, nil
}
return join.Next()
}

// TODO: add some tests that either return error if the doc is not found or return
// the related doc (without this one) and let it be filtered.
if !hasDoc {
if firstSide.isParent {
join.docsToYield = append(join.docsToYield, firstSide.plan.Value())
return true, nil
if !firstSide.isParent {
for i := range join.encounteredDocIDs {
if join.encounteredDocIDs[i] == secondaryDocID {
return join.Next()
}
return join.Next()
}
join.encounteredDocIDs = append(join.encounteredDocIDs, secondaryDocID)
}

if join.parentSide.relFieldDef.Kind.IsArray() {
var primaryDocs []core.Doc
var secondaryDoc core.Doc
if join.skipChild {
primaryDocs, secondaryDoc = joinPrimaryDocs([]core.Doc{firstSide.plan.Value()}, secondSide, firstSide)
} else {
primaryDocs, secondaryDoc, err = join.fetchPrimaryDocsReferencingSecondaryDoc()
if err != nil {
return false, err
}
}
secondaryDoc.Fields[join.childSelect.Index] = primaryDocs
// check if there can ever be false (a.k.a. hasDoc = false)
hasDoc, err := fetchDocWithID(secondSide.plan, secondaryDocID)
if err != nil {
return false, err
}

join.docsToYield = append(join.docsToYield, secondaryDoc)
} else {
parentDoc := join.parentSide.plan.Value()
parentDoc.Fields[join.parentSide.relFieldMapIndex.Value()] = join.childSide.plan.Value()
join.docsToYield = append(join.docsToYield, parentDoc)
}
} else {
primaryDocs, secondaryDoc, err := join.fetchPrimaryDocsReferencingSecondaryDoc()
if err != nil {
return false, err
// TODO: add some tests that either return error if the doc is not found or return
// the related doc (without this one) and let it be filtered.
if !hasDoc {
if firstSide.isParent {
join.docsToYield = append(join.docsToYield, firstSide.plan.Value())
return true, nil
}
if join.parentSide.isPrimary() {
join.docsToYield = append(join.docsToYield, primaryDocs...)
return join.Next()
}

if join.parentSide.relFieldDef.Kind.IsArray() {
var primaryDocs []core.Doc
var secondaryDoc core.Doc
// if child is not requested as part of the response, we just add the existing one (fetched by the secondary index
// on a filtered value) so that top select node that runs the filter again can yield it.
if join.skipChild {
primaryDocs, secondaryDoc = joinPrimaryDocs([]core.Doc{firstSide.plan.Value()}, secondSide, firstSide)
} else {
join.docsToYield = append(join.docsToYield, secondaryDoc)
primaryDocs, secondaryDoc, err = join.fetchPrimaryDocsReferencingSecondaryDoc()
if err != nil {
return false, err
}
}
}
secondaryDoc.Fields[join.parentSide.relFieldMapIndex.Value()] = primaryDocs

join.docsToYield = append(join.docsToYield, secondaryDoc)
} else {
parentDoc := join.parentSide.plan.Value()
parentDoc.Fields[join.parentSide.relFieldMapIndex.Value()] = join.childSide.plan.Value()
join.docsToYield = append(join.docsToYield, parentDoc)
}
return true, nil
}

Expand All @@ -792,7 +768,8 @@ func (join *invertibleTypeJoin) invertJoinDirectionWithIndex(
s.filter = fieldFilter
s.initFetcher(immutable.Option[string]{}, immutable.Some(index))

join.invert()
join.childSide.isFirst = join.parentSide.isFirst
join.parentSide.isFirst = !join.parentSide.isFirst

return nil
}
Expand Down

0 comments on commit 9d44040

Please sign in to comment.