Atomic Query Construction (AQC) Query Optimization Backend Development Software Architecture

Composing Clean API Queries with jQuery DataTables and Atomic Query Construction

Muhammad Raheel

Muhammad Raheel

March 23rd, 2026 · 5 min read

Composing Clean API Queries with jQuery DataTables and Atomic Query Construction

When I work with jQuery DataTables, I only send filters that actually have values. Nothing more, nothing less. For example:

"data": function (d) {
    if ($('#category_id').val() > 0) {
        d['category_id'] = $('#category_id').val();
    }

    if ($('#brand_id').val() > 0) {
        d['brand_id'] = $('#brand_id').val();
    }

    if ($('#keyword').val() != "") {
        d['keyword'] = $('#keyword').val();
    }
}

Each filter is included only if it exists. Empty or irrelevant values are ignored. This ensures the backend only receives meaningful data.

Backend with AQC: Composition in Action

On the backend, I use the Atomic Query Construction (AQC) pattern. AQC lets us compose small, independent filter blocks, applying only the filters that exist in the request. For example:

$query = Product::query();

if ($this->category_id) {
    $query->where('category_id', $this->category_id);
}

if ($this->brand_id) {
    $query->where('brand_id', $this->brand_id);
}

if ($this->keyword) {
    $query->where('name', 'like', "%{$this->keyword}%");
}

return $query->get();

Here, each block is independent. Since we have three optional filters, there are eight possible combinations of these filters:  

  • No filter means fetch all
  • category_id only
  • brand_id only
  • keyword only
  • category_id + brand_id
  • category_id + keyword
  • brand_id + keyword
  • category_id + brand_id + keyword

AQC handles all these combinations automatically. There’s no need for:

  • Repository pattern just to separate queries
  • Query object pattern for every possible filter combination

Everything is handled by composing small, reusable filter blocks. Adding a new filter is as simple as adding another if block.   

if ($this->status) {
    $query->where('status', $this->status);
}

All combinations now include the new filter naturally, without touching existing code.

Frontend and Backend Alignment

The frontend decides which filters are active. The backend applies only those filters using AQC composition.

Layer Responsibility
Frontend Send only active filters
Backend Apply filters conditionally and compose query

Why Composition Matters

  • Each filter is independent and reusable
  • All possible combinations of filters are handled automatically
  • No duplication of queries or classes
  • No need for repository or query object patterns for conditional filtering
  • Adding a new filter doesn’t break existing code
  • Frontend and backend stay aligned naturally

By combining conditional frontend filters with AQC composition, filtering becomes clean, scalable, and flexible — no matter how many parameters exist.

Final Thoughts

When filters are optional, the real problem is not writing queries. It’s handling combinations.

With three filters, there are already eight combinations. Add more, and it grows fast. Trying to handle this manually with repositories, query objects, or separate methods only increases complexity.

AQC solves this by using composition. Each filter is a small, independent piece, and the final query is built by combining only what exists.

On the frontend, jQuery DataTables already gives you a simple way to send only active filters. On the backend, AQC applies only those filters. Both sides follow the same rule, without extra coordination.

This removes unnecessary patterns, reduces duplication, and keeps the code easy to extend.

In the end, it’s not about DataTables or AQC separately. It’s about keeping both layers consistent and letting composition handle the complexity instead of writing it yourself.

Comments


Comment created and will be displayed once approved.