alias()); } public function shouldRender(Query $query): bool { $criteria = $query->getFieldCriteria($this->schema->type()); return $criteria instanceof Criteria && $criteria->isAllowedField($this->getKey()); } public function render(Model $model): mixed { return $model->getAttribute($this->alias()); } public function getSort(): Sort { return new Sort(key: $this->alias(), qualifyColumn: QualifyColumn::NO); } /** * Determine if the aggregate value should be included in the select clause of our query. */ public function shouldAggregate(Query $query): bool { // Select aggregate if explicitly included in sparse fieldsets $fieldCriteria = $query->getFieldCriteria($this->schema->type()); if ($fieldCriteria instanceof Criteria && $fieldCriteria->isAllowedField($this->getKey())) { return true; } $scope = ScopeParser::parse($this->schema->type()); // Select aggregate if filtering on the aggregate value $filter = $this->getFilter(); foreach ($query->getFilterCriteria() as $criteria) { if ($criteria->shouldFilter($filter, $scope)) { return true; } } // Select aggregate if sorting on the aggregate value $sort = $this->getSort(); return array_any($query->getSortCriteria(), fn ($sortCriterion): bool => $sortCriterion->shouldSort($sort, $scope)); } /** * Load the aggregate field value for the model. */ public function load(Query $query, Model $model): Model { $constrainedRelation = []; $relationSchema = $this->schema->relation($this->relation); $constrainedRelation[$this->relation] = function (Builder $relationBuilder) use ($query, $relationSchema): void { if ($relationSchema instanceof Schema) { // TODO: distinguish scope from type $scope = ScopeParser::parse($this->relation); $this->filter($relationBuilder, $query, $relationSchema, $scope); } }; return $model->loadAggregate($constrainedRelation, $this->aggregateColumn, $this->function->value); } /** * Eager load the aggregate value for the query builder. */ public function with(Query $query, Builder $builder): Builder { $constrainedRelation = []; $relationSchema = $this->schema->relation($this->relation); $constrainedRelation[$this->relation] = function (Builder $relationBuilder) use ($query, $relationSchema): void { if ($relationSchema instanceof Schema) { // TODO: distinguish scope from type $scope = ScopeParser::parse($this->relation); $this->filter($relationBuilder, $query, $relationSchema, $scope); } }; return $builder->withAggregate($constrainedRelation, $this->aggregateColumn, $this->function->value); } /** * Format the aggregate value to its sub-select alias / model attribute. */ public function alias(): string { return Str::of($this->relation) ->append('_') ->append($this->function->value) ->__toString(); } }