ColumnMappedSet.php

PHP

Path: src/Table/Utility/ColumnMappedSet.php

<?php

namespace mini\Table\Utility;

use IteratorAggregate;
use mini\Table\Contracts\SetInterface;
use Traversable;

/**
 * Wraps a SetInterface to remap column names
 *
 * Used when a subquery returns a different column name than the outer
 * query expects. For example:
 *
 * ```php
 * // Subquery: SELECT user_id FROM orders
 * // Outer: WHERE id IN (subquery)
 * // Need to map 'user_id' -> 'id' for has() calls
 *
 * $mapped = new ColumnMappedSet($subqueryResult, 'user_id', 'id');
 * $table->in('id', $mapped);
 * ```
 */
class ColumnMappedSet implements SetInterface, IteratorAggregate
{
    /**
     * @param SetInterface $source The source set to wrap
     * @param string $sourceColumn Column name in the source set
     * @param string $targetColumn Column name expected by the consumer
     */
    public function __construct(
        private SetInterface $source,
        private string $sourceColumn,
        private string $targetColumn,
    ) {}

    public function getColumns(): array
    {
        $sourceCols = $this->source->getColumns();
        if (!isset($sourceCols[$this->sourceColumn])) {
            throw new \LogicException(
                "Source set does not have column '{$this->sourceColumn}'"
            );
        }

        // Return with remapped column name
        return [$this->targetColumn => $sourceCols[$this->sourceColumn]];
    }

    public function has(object $member): bool
    {
        // Consumer passes member with target column name, we translate to source
        if (!property_exists($member, $this->targetColumn)) {
            throw new \InvalidArgumentException(
                "Member missing property: {$this->targetColumn}"
            );
        }

        $mapped = new \stdClass();
        $mapped->{$this->sourceColumn} = $member->{$this->targetColumn};

        return $this->source->has($mapped);
    }

    public function getIterator(): Traversable
    {
        // Yield rows with remapped column name
        foreach ($this->source as $row) {
            $mapped = new \stdClass();
            $mapped->{$this->targetColumn} = $row->{$this->sourceColumn};
            yield $mapped;
        }
    }
}