Documentation Index
Fetch the complete documentation index at: https://docs.fiquela.io/llms.txt
Use this file to discover all available pages before exploring further.
FiQueLa supports rich filtering through WHERE (pre-aggregation) and HAVING (post-aggregation) conditions. Both use the same operator set and can be combined with logical operators and groups.
FiQueLa 3.0 — the field argument of where() and having() accepts any SQL expression, not just a plain field name. Function calls, infix arithmetic, and nested expressions are all evaluated by the runtime expression evaluator before the operator is applied.use FQL\Enum\Operator;
// Field name (classic form)
$query->where('email', Operator::LIKE, '%@example.com');
// Function call as the left-hand side
$query->where('LOWER(name)', Operator::EQUAL, 'alice');
// Infix arithmetic
$query->where('price * (1 + vat_rate)', Operator::GREATER_THAN, 100);
// Nested function calls
$query->having('SUM(price * qty)', Operator::GREATER_THAN, 1000);
WHERE vs HAVING
| Clause | When it runs | Use for |
|---|
WHERE | Before grouping and aggregation | Filtering raw rows |
HAVING | After grouping and aggregation | Filtering aggregated results |
use FQL\Enum\Operator;
$query->count('id')->as('total')
->sum('price')->as('revenue')
->groupBy('category')
->where('price', Operator::GREATER_THAN, 0) // filters raw rows first
->having('total', Operator::GREATER_THAN, 5); // filters after grouping
Comparison operators
Import the Operator enum before using operators in the fluent API:
| Enum constant | Operator | Description |
|---|
EQUAL | = | Loose equality |
EQUAL_STRICT | == | Strict equality (type-safe) |
NOT_EQUAL | != | Loose inequality |
NOT_EQUAL_STRICT | !== | Strict inequality (type-safe) |
GREATER_THAN | > | Greater than |
GREATER_THAN_OR_EQUAL | >= | Greater than or equal |
LESS_THAN | < | Less than |
LESS_THAN_OR_EQUAL | <= | Less than or equal |
IN | IN | Field value is in the given array |
NOT_IN | NOT IN | Field value is not in the given array |
LIKE | LIKE | Pattern match — _ matches one character, % matches any sequence |
NOT_LIKE | NOT LIKE | Inverse of LIKE |
REGEXP | REGEXP | Match against a regular expression pattern |
NOT_REGEXP | NOT REGEXP | Inverse of REGEXP |
IS | IS | Type check — see IS operator section below |
NOT_IS | IS NOT | Inverse type check |
BETWEEN | BETWEEN | Field value is between two values (inclusive) |
NOT_BETWEEN | NOT BETWEEN | Inverse of BETWEEN |
Logical operators
Chain multiple conditions using logical operators:
$query->where('price', Operator::GREATER_THAN, 100)
->and('stock', Operator::GREATER_THAN, 0)
->or('featured', Operator::EQUAL, true)
->xor('clearance', Operator::EQUAL, true);
In FQL strings:
WHERE price > 100
AND stock > 0
OR featured = true
Basic examples
use FQL\Enum\Operator;
// Comparison
$query->where('price', Operator::GREATER_THAN, 100);
// IN list
$query->where('status', Operator::IN, ['active', 'pending']);
// BETWEEN
$query->where('price', Operator::BETWEEN, [300, 500]);
// LIKE — wildcard matching
$query->where('description', Operator::LIKE, '%wireless%');
// REGEXP
$query->where('name', Operator::REGEXP, '^Product [A-B]$');
LIKE pattern matching
The LIKE operator follows MySQL conventions:
| Wildcard | Matches |
|---|
% | Any sequence of characters (including empty) |
_ | Exactly one character |
// Ends with 'Pro'
$query->where('name', Operator::LIKE, '%Pro');
// Starts with 'Widget'
$query->where('name', Operator::LIKE, 'Widget%');
// Contains 'cable'
$query->where('name', Operator::LIKE, '%cable%');
// Exactly 5 characters
$query->where('code', Operator::LIKE, '_____');
Matching is case-insensitive.
REGEXP pattern matching
The REGEXP operator accepts a regular expression pattern. If the pattern includes delimiters (e.g. /pattern/i), they are used as-is. Otherwise the pattern is wrapped in / delimiters automatically.
$query->where('sku', Operator::REGEXP, '^[A-Z]{2}-\\d{4}$');
$query->where('name', Operator::REGEXP, '^Product [A-C]');
WHERE sku REGEXP "^[A-Z]{2}-\d{4}$"
IS operator — type checking
The IS and IS NOT operators check the PHP type of a field value. Pass a Type enum constant as the right-hand operand:
use FQL\Enum\Operator;
use FQL\Enum\Type;
$query->where('price', Operator::IS, Type::NUMBER);
$query->where('tags', Operator::IS, Type::ARRAY);
$query->where('deletedAt', Operator::IS, Type::NULL);
$query->where('active', Operator::NOT_IS, Type::FALSE);
| Type constant | PHP type check |
|---|
Type::BOOLEAN | is_bool() |
Type::TRUE | === true |
Type::FALSE | === false |
Type::NUMBER | is_numeric() |
Type::INTEGER | is_integer() |
Type::FLOAT | is_float() |
Type::STRING | is_string() |
Type::NULL | is_null() |
Type::ARRAY | is_array() |
Type::OBJECT | is_object() |
In FQL strings, use the type name directly:
WHERE price IS NUMBER
WHERE tags IS ARRAY
WHERE deletedAt IS NULL
WHERE active IS NOT FALSE
Condition grouping
Group conditions with whereGroup(), andGroup(), orGroup(), havingGroup(), and endGroup() to build complex logic. Use havingGroup() specifically to start a grouped condition within the HAVING context:
$query->where('price', Operator::GREATER_THAN, 100)
->andGroup()
->where('description', Operator::LIKE, '%very usefully')
->or('price', Operator::LESS_THAN_OR_EQUAL, 300)
->orGroup()
->where('price', Operator::EQUAL, 200)
->and('description', Operator::LIKE, '%very usefully')
->endGroup()
->endGroup()
->orGroup()
->where('price', Operator::LESS_THAN_OR_EQUAL, 300)
->endGroup();
This produces the SQL-equivalent:
price > 100
AND (
description LIKE '%very usefully'
OR price <= 300
OR (
price = 200
AND description LIKE '%very usefully'
)
)
OR (
price <= 300
)
FQL strings also support parentheses for condition grouping:
WHERE price > 100
AND (description LIKE "%very usefully" OR price <= 300)