Skip to main content

Overview

Namespace: FQL\Results ResultsProvider is the abstract base class for result sets returned by Query::execute(). It implements IteratorAggregate and provides methods to iterate, fetch individual rows, perform aggregate calculations, and export results to a file. You never instantiate ResultsProvider directly — you receive it from execute().
use FQL\Query\Provider;

$results = Provider::fromFile('orders.json')
    ->select('id', 'total', 'status')
    ->where('status', \FQL\Enum\Operator::EQUAL, 'paid')
    ->execute();

echo $results->count();      // 42
echo $results->sum('total'); // 18340.00

Subtypes

Query::execute() returns one of two concrete implementations depending on query complexity:
ClassWhen used
Results\StreamSimple queries without joins or sorting. Processes data lazily as a generator — low memory usage.
Results\InMemoryQueries with joins, sorting, or DISTINCT. Loads all rows into an ArrayIterator before returning.
You can force a specific mode by passing the class name to execute():
use FQL\Results\InMemory;

$results = $query->execute(InMemory::class);
Both classes expose the same ResultsProvider interface described below.

Iteration

getIterator()

Returns a Traversable over all result rows. Each row is an associative array.
public function getIterator(): \Traversable
ResultsProvider implements IteratorAggregate, so you can use it in a foreach loop directly.
foreach ($results as $row) {
    echo $row['name'];
}

Fetching rows

fetchAll()

Yield all rows as a Generator. Optionally hydrate each row into a DTO class.
public function fetchAll(?string $dto = null): \Generator
dto
string | null
Fully qualified class name of a DTO. When provided, each row is mapped to an instance of that class using constructor parameters or public properties.
returns
Generator
Yields associative arrays (or DTO objects when $dto is set).
foreach ($results->fetchAll() as $row) {
    echo $row['id'] . ': ' . $row['name'];
}

// Hydrate into a DTO
class ProductDto {
    public function __construct(
        public readonly int $id,
        public readonly string $name,
        public readonly float $price,
    ) {}
}

foreach ($results->fetchAll(ProductDto::class) as $product) {
    echo $product->name;
}

fetch()

Return the first row only, or null if the result set is empty.
public function fetch(?string $dto = null): mixed
dto
string | null
Optional DTO class name for hydration.
returns
array | object | null
The first row as an associative array, a DTO object, or null.
$product = $results->fetch();
if ($product !== null) {
    echo $product['name'];
}

fetchSingle()

Return a single field value from the first row.
public function fetchSingle(string $field): mixed
field
string
required
Field name, including dot-notation for nested fields (e.g. address.city).
returns
mixed
The value of the field, or null if the row or field does not exist.
$name = $results->fetchSingle('name');
$city = $results->fetchSingle('address.city');

fetchNth()

Yield every nth row, or every even/odd row.
public function fetchNth(int|string $n, ?string $dto = null): \Generator
n
int | 'even' | 'odd'
required
  • Integer: yield every nth row (1-indexed count).
  • 'even': yield rows at even positions (0-indexed: 0, 2, 4…).
  • 'odd': yield rows at odd positions (0-indexed: 1, 3, 5…).
dto
string | null
Optional DTO class name.
Throws: InvalidArgumentException for invalid $n values.
// Every 3rd row
foreach ($results->fetchNth(3) as $row) { ... }

// Even-positioned rows
foreach ($results->fetchNth('even') as $row) { ... }

exists()

Return true if the result set contains at least one row.
public function exists(): bool
if ($results->exists()) {
    echo 'Found records';
}

Counting

count()

Return the total number of rows in the result set.
public function count(): int
Results\Stream caches the count internally after the first call, so repeated count() calls do not re-read the file.
echo $results->count(); // e.g. 1024

Aggregation

These methods iterate the result set and compute aggregate values. For Results\Stream, computed values are cached so that repeated calls do not re-read the stream.

sum()

public function sum(string $field): float
field
string
required
Field name to sum. Non-numeric values are treated as 0.

avg()

public function avg(string $field, int $decimalPlaces = 2): float
field
string
required
Field name to average.
decimalPlaces
int
Number of decimal places in the result (default 2).

min()

public function min(string $field): float
field
string
required
Field name to find the minimum of.

max()

public function max(string $field): float
field
string
required
Field name to find the maximum of.
$total   = $results->sum('price');        // 4850.00
$average = $results->avg('price', 2);     // 121.25
$lowest  = $results->min('price');        // 9.99
$highest = $results->max('price');        // 499.00

Exporting

into()

Write all result rows to a file. The output format is determined by the file extension in the FileQuery string.
public function into(string|FileQuery $target): ?string
target
string | FileQuery
required
A file path string (e.g. output/report.csv) or a FileQuery object. The directory is created automatically if it does not exist.
returns
string | null
The resolved output file path, or null when running under EXPLAIN ANALYZE mode.
Throws: FileQueryException, InvalidFormatException, InvalidArgumentException
// Export to JSON
$results->into('json(output/filtered.json).root.items');

// Export to CSV
$results->into('csv(output/report.csv)');

// Export to XML
$results->into('xml(output/report.xml).ROOT.ROW');

// Using a FileQuery object
use FQL\Query\FileQuery;
$results->into(new FileQuery('csv(exports/products.csv)'));
Calling aggregation methods (sum, avg, etc.) before into() on a Results\Stream will exhaust the generator. Call into() first, or use Results\InMemory.