One question keeps appearing whenever someone looks at the Atomic Query Construction (AQC) pattern for the first time:

At first glance, DTOs sound like the “cleaner” solution. They provide type safety, structure, and explicit contracts. In many architectures, DTOs make perfect sense.

But AQC is intentionally designed around arrays, and replacing them with DTOs would undermine one of the core ideas of the pattern.

To understand why, we need to look at how AQC actually works.

AQC Is Parameter-Driven

The central idea behind AQC is simple:

Each parameter activates a specific atomic piece of logic.

For example:

                                $params = [
    'category_id' => 5,
    'min_price' => 100,
    'max_price' => 500,
    'with' => ['brand']
];
                            

Inside the query class:

                                $query = Product::query();

if (!empty($params['category_id'])) {
    $query->where('category_id', $params['category_id']);
}

if (!empty($params['min_price'])) {
    $query->where('price', '>=', $params['min_price']);
}

if (!empty($params['max_price'])) {
    $query->where('price', '<=', $params['max_price']);
}

if (!empty($params['with'])) {
    $query->with($params['with']);
}
                            

Each parameter independently contributes to the final query.

This means query composition is dynamic.

And this is where arrays become important.

The Cartesian Flexibility of Parameters

AQC relies on the idea that parameters can combine freely.

If you have five optional parameters:

                                category_id
brand_id
price_min
price_max
with
                            

You don't just have five scenarios.

You have dozens of possible combinations.

Examples:

                                category_id
category_id + brand_id
category_id + price_min
brand_id + price_max
price_min + price_max
category_id + brand_id + with
brand_id + price_min + price_max
                            

The number of combinations grows quickly.

Arrays allow this naturally because parameters are simply present or absent.

Each parameter acts like a switch that activates a piece of query logic.

DTOs don't work well in this environment because they encourage rigid structures, where every field is predefined and expected.

AQC is not designed for rigid structures.

It is designed for combinatorial flexibility.

DTOs Introduce Unnecessary Rigidity

A DTO typically looks like this:

                                class ProductQueryDTO
{
    public ?int $categoryId;
    public ?int $brandId;
    public ?int $priceMin;
    public ?int $priceMax;
}
                            

This immediately creates a few problems.

1. DTOs Define Structure Too Early

DTOs force you to define all possible parameters upfront.

But queries evolve.

Tomorrow you may add:

                                min_stock
max_stock
rating
visibility
published_at
                            

Now your DTO grows. Then another developer creates another DTO for a slightly different query.

Soon you have DTOs multiplying.

2. DTOs Add an Extra Layer

AQC classes already serve a single purpose: build and execute queries.

Introducing DTOs means adding a translation layer:

                                Request → DTO → AQC → Query
                            

With arrays the flow stays simple:

                                Request → AQC → Query
                            

AQC intentionally avoids unnecessary layers.

3. DTOs Reduce Dynamic Composition

DTOs imply a fixed contract.

But AQC is built on conditional query pieces.

Each parameter activates a piece of logic.

Arrays support that naturally because they allow parameters to appear or disappear without forcing structural constraints.

Arrays Match the Philosophy of AQC

AQC is built on a few clear ideas:

  • One class = one intention
  • Parameters control query behavior
  • Queries are composed conditionally
  • Controllers remain thin

Arrays align perfectly with this philosophy.

Each parameter acts as a trigger for an atomic query segment.

That makes the query builder inside the AQC class extremely flexible without introducing complexity elsewhere.

Final Thought

DTOs are useful in many architectural patterns.

But AQC is intentionally parameter-driven, and arrays preserve the dynamic nature of query composition.

Each parameter activates an atomic query piece, and arrays allow those pieces to combine freely into a Cartesian number of possible query scenarios.

Trying to force DTOs into this pattern doesn't improve it.

It just makes the system heavier while removing the flexibility AQC was designed to provide.

Comments


Comment created and will be displayed once approved.