Query Structure

ObjectQuel is inspired by QUEL, the query language from UC Berkeley's Ingres project. Unlike SQL's table-centric approach, ObjectQuel works directly with your domain entities using object-oriented syntax, and supports wildcards, regex, and full-text search alongside standard comparison operators.

explanation

The elements of a query

Every ObjectQuel query is built from up to six clauses, written in this order:

Query configuration diagram

Clauses at a Glance

  • Flags (optional) — Written before all other clauses, flags adjust query execution behavior. For example, @InValuesAreFinal tells the optimizer that every value in an IN list will match exactly one row.
  • Range definitions (required) — Declare which entities you are querying and assign each one a short alias. Every alias used in retrieve, where, or sort by must be declared here first.
  • retrieve (required) — Specifies what to return: full entity objects, specific properties, or a mix. The optional unique modifier removes duplicate rows.
  • where (optional) — Filters results using comparisons, set membership, null checks, and function calls.
  • sort by (optional) — Orders results. Multiple fields are evaluated left-to-right as tie-breakers.
  • window (optional) — Paginates results by page number and page size. Always pair with sort by to keep page boundaries stable.

Query Optimization Flags

Flags are optional and only needed in specific optimization scenarios.

@InValuesAreFinal

By default, ObjectQuel scans all rows even when using an IN clause, because it cannot know whether a column is unique without being told. The @InValuesAreFinal flag asserts that each value in the IN list matches exactly one row, allowing the query planner to stop as soon as all values have been found:

$results = $entityManager->executeQuery("
    @InValuesAreFinal
    range of p is App\\Entity\\ProductEntity
    retrieve (p) where p.productId in (:ids)
", ['ids' => [1, 2, 3, 4, 5]]);
Only use @InValuesAreFinal when the IN clause targets a primary key or unique column. Applying it to a non-unique column will cause the query to return incomplete results.