Skip to content

Commit 7622f59

Browse files
abnegateclaude
andcommitted
perf(relationships): drop Attribute::fromDocument allocation in hot loops
afterDocumentCreate/Update and populateDocuments each instantiated a new Attribute object per relationship per call just to read .key (and sometimes .type), which the underlying Document already exposes via getAttribute(). For populateDocuments specifically this fired on every relationship across every batch traversal at every depth. Replace with direct getAttribute('key', $relationship->getId()) and the existing Attribute::isRelationship static helper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 39851ac commit 7622f59

1 file changed

Lines changed: 21 additions & 14 deletions

File tree

src/Database/Hook/Relationships.php

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ public function afterDocumentCreate(Document $collection, Document $document): D
143143
$stackCount = \count($this->writeStack);
144144

145145
foreach ($relationships as $relationship) {
146-
$typedRelAttr = Attribute::fromDocument($relationship);
147-
$key = $typedRelAttr->key;
146+
/** @var string $key */
147+
$key = $relationship->getAttribute('key', $relationship->getId());
148148
$value = $document->getAttribute($key);
149149
$rel = RelationshipVO::fromDocument($collection->getId(), $relationship);
150150
$relatedCollection = $this->db->getCollection($rel->relatedCollection);
@@ -293,8 +293,8 @@ public function afterDocumentUpdate(Document $collection, Document $old, Documen
293293
$stackCount = \count($this->writeStack);
294294

295295
foreach ($relationships as $index => $relationship) {
296-
$typedRelAttr = Attribute::fromDocument($relationship);
297-
$key = $typedRelAttr->key;
296+
/** @var string $key */
297+
$key = $relationship->getAttribute('key', $relationship->getId());
298298
$value = $document->getAttribute($key);
299299

300300
$value = $this->coerceToDocument($document, $key, $value);
@@ -819,21 +819,28 @@ public function populateDocuments(array $documents, Document $collection, int $f
819819
$relationships = [];
820820

821821
foreach ($popAttributes as $attribute) {
822-
$typedPopAttr = Attribute::fromDocument($attribute);
823-
if ($typedPopAttr->type === ColumnType::Relationship) {
824-
if ($typedPopAttr->key === $skipKey) {
825-
continue;
826-
}
822+
// Avoid the Attribute::fromDocument allocation —
823+
// we only need the type and key here, both of
824+
// which are plain Document attributes.
825+
if (! Attribute::isRelationship($attribute)) {
826+
continue;
827+
}
827828

828-
if (! $parentHasExplicitSelects || \array_key_exists($typedPopAttr->key, $sels)) {
829-
$relationships[] = $attribute;
830-
}
829+
/** @var string $popKey */
830+
$popKey = $attribute->getAttribute('key', $attribute->getId());
831+
832+
if ($popKey === $skipKey) {
833+
continue;
834+
}
835+
836+
if (! $parentHasExplicitSelects || \array_key_exists($popKey, $sels)) {
837+
$relationships[] = $attribute;
831838
}
832839
}
833840

834841
foreach ($relationships as $relationship) {
835-
$typedRelAttr = Attribute::fromDocument($relationship);
836-
$key = $typedRelAttr->key;
842+
/** @var string $key */
843+
$key = $relationship->getAttribute('key', $relationship->getId());
837844
$queries = $sels[$key] ?? [];
838845
$relationship->setAttribute('collection', $coll->getId());
839846
$isAtMaxDepth = ($currentDepth + 1) >= Database::RELATION_MAX_DEPTH;

0 commit comments

Comments
 (0)