Skip to content

Commit 03e33c7

Browse files
Merge pull request #28 from CodeWithDennis/optimize-queries
Optimize queries
2 parents db3bd2e + 7cb3d7b commit 03e33c7

File tree

1 file changed

+63
-22
lines changed

1 file changed

+63
-22
lines changed

src/SelectTree.php

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,40 +81,81 @@ protected function setUp(): void
8181
});
8282
}
8383

84-
private function buildTree($parent = null): array|Collection
84+
private function buildTree(): Collection
85+
{
86+
// Start with two separate query builders
87+
$nullParentQuery = $this->getRelationship()->getRelated()->query()->where($this->getParentAttribute(), $this->getParentNullValue());
88+
$nonNullParentQuery = $this->getRelationship()->getRelated()->query()->whereNot($this->getParentAttribute(), $this->getParentNullValue());
89+
90+
// If we're not at the root level and a modification callback is provided, apply it to null query
91+
if ($this->modifyQueryUsing) {
92+
$nullParentQuery = $this->evaluate($this->modifyQueryUsing, ['query' => $nullParentQuery]);
93+
}
94+
95+
// Fetch results for both queries
96+
$nullParentResults = $nullParentQuery->get();
97+
$nonNullParentResults = $nonNullParentQuery->get();
98+
99+
// Combine the results from both queries
100+
$combinedResults = $nullParentResults->concat($nonNullParentResults);
101+
102+
return $this->buildTreeFromResults($combinedResults);
103+
}
104+
105+
private function buildTreeFromResults($results, $parent = null): Collection
85106
{
86107
// Assign the parent's null value to the $parent variable if it's not null
87108
if ($parent == null || $parent == $this->getParentNullValue()) {
88109
$parent = $this->getParentNullValue() ?? $parent;
89110
}
90111

91-
// Create a default query to retrieve related items.
92-
$defaultQuery = $this->getRelationship()
93-
->getRelated()
94-
->query()
95-
->where($this->getParentAttribute(), $parent);
112+
// Create a collection to store the tree
113+
$tree = collect();
96114

97-
// If we're not at the root level and a modification callback is provided, apply it to the query.
98-
if (! $parent && $this->modifyQueryUsing) {
99-
$defaultQuery = $this->evaluate($this->modifyQueryUsing, ['query' => $defaultQuery]);
115+
// Create a mapping of results by their parent IDs for faster lookup
116+
$resultMap = [];
117+
118+
// Group results by their parent IDs
119+
foreach ($results as $result) {
120+
$parentId = $result->{$this->getParentAttribute()};
121+
if (! isset($resultMap[$parentId])) {
122+
$resultMap[$parentId] = [];
123+
}
124+
$resultMap[$parentId][] = $result;
100125
}
101126

102-
// Fetch the results from the default query.
103-
$results = $defaultQuery->get();
127+
// Recursively build the tree starting from the root (null parent)
128+
$rootResults = $resultMap[$parent] ?? [];
129+
foreach ($rootResults as $result) {
130+
// Build a node and add it to the tree
131+
$node = $this->buildNode($result, $resultMap);
132+
$tree->push($node);
133+
}
104134

105-
// Map the results into a tree structure.
106-
return $results->map(function ($result) {
135+
return $tree;
136+
}
107137

108-
// Recursively build children trees for the current result.
109-
$children = $this->buildTree($result->id);
138+
private function buildNode($result, $resultMap): array
139+
{
140+
// Create a node with 'name' and 'value' attributes
141+
$node = [
142+
'name' => $result->{$this->getTitleAttribute()},
143+
'value' => $result->id,
144+
];
145+
146+
// Check if the result has children
147+
if (isset($resultMap[$result->id])) {
148+
$children = collect();
149+
// Recursively build child nodes
150+
foreach ($resultMap[$result->id] as $child) {
151+
$childNode = $this->buildNode($child, $resultMap);
152+
$children->push($childNode);
153+
}
154+
// Add children to the node
155+
$node['children'] = $children->toArray();
156+
}
110157

111-
// Create an array representation of the current result with children.
112-
return [
113-
'name' => $result->{$this->getTitleAttribute()},
114-
'value' => $result->id,
115-
'children' => $children->isEmpty() ? null : $children->toArray(),
116-
];
117-
});
158+
return $node;
118159
}
119160

120161
public function relationship(string $relationship, string $titleAttribute, string $parentAttribute, Closure $modifyQueryUsing = null): self

0 commit comments

Comments
 (0)