<?php

declare(strict_types=1);

namespace App\Framework\Database\Criteria;

use App\Framework\Database\Criteria\Projection\{
    AggregateProjection,
    ProjectionList,
    PropertyProjection
};

/**
 * Static factory class for creating projections
 */
final class Projections
{
    private function __construct()
    {
    }

    /**
     * Property projection
     */
    public static function property(string $property, ?string $alias = null): Projection
    {
        return new PropertyProjection($property, $alias);
    }

    /**
     * COUNT aggregate
     */
    public static function count(string $property = '*', ?string $alias = null): Projection
    {
        return new AggregateProjection('COUNT', $property, $alias);
    }

    /**
     * COUNT DISTINCT aggregate
     */
    public static function countDistinct(string $property, ?string $alias = null): Projection
    {
        return new AggregateProjection('COUNT', "DISTINCT {$property}", $alias);
    }

    /**
     * SUM aggregate
     */
    public static function sum(string $property, ?string $alias = null): Projection
    {
        return new AggregateProjection('SUM', $property, $alias);
    }

    /**
     * AVG aggregate
     */
    public static function avg(string $property, ?string $alias = null): Projection
    {
        return new AggregateProjection('AVG', $property, $alias);
    }

    /**
     * MIN aggregate
     */
    public static function min(string $property, ?string $alias = null): Projection
    {
        return new AggregateProjection('MIN', $property, $alias);
    }

    /**
     * MAX aggregate
     */
    public static function max(string $property, ?string $alias = null): Projection
    {
        return new AggregateProjection('MAX', $property, $alias);
    }

    /**
     * Projection list
     */
    public static function projectionList(Projection ...$projections): Projection
    {
        return new ProjectionList(...$projections);
    }

    /**
     * Row count projection (shorthand)
     */
    public static function rowCount(?string $alias = 'count'): Projection
    {
        return self::count('*', $alias);
    }
}
