Clauses
The abstract class pine3ree\Db\Sql\Clause is the base class for implementations
that abstract common SQL clauses such as the JOIN clause and the conditional
clauses WHERE, HAVING and ON.
The Where, Having and On conditional clauses
A conditional clause wraps a search condition object as an instance of Predicate\Set
It also provides proxy methods to all the condition building methods of a predicate-set.
After the first call of any of such methods we are brought into the context of the
composed predicate-set.
use pine3ree\Db\Sql\Params;
use pine3ree\Db\Sql\Predicate;
ConditionalClause::getSearchCondition(): Predicate\Set;
ConditionalClause::isEmpty(): bool
ConditionalClause::hasParams(): bool
ConditionalClause::getParams(): ?Params
ConditionalClause::getSQL(DriverInterface $driver = null, Params $params = null): string
/**
 * @param Predicate|string|array $predicate A Predicate|Predicate\Set instance
 *      or a specs-array [identifier, operator, value] or [identifier => value]
 */
ConditionalClause::addPredicate($predicate): Predicate\Set;
ConditionalClause::literal(string $literal): Predicate\Set;
ConditionalClause::expression(string $expression, array $substitutions = []): Predicate\Set;
ConditionalClause::expr(string $expression, array $substitutions = []): Predicate\Set;
ConditionalClause::all($identifier, string $operator, Select $select): Predicate\Set;
ConditionalClause::any($identifier, string $operator, Select $select): Predicate\Set;
ConditionalClause::some($identifier, string $operator, Select $select): Predicate\Set;
ConditionalClause::between($identifier, $min_value, $max_value): Predicate\Set;
ConditionalClause::notBetween($identifier, $min_value, $max_value): Predicate\Set;
ConditionalClause::exists(Select $select): Predicate\Set;
ConditionalClause::notExists(Select $select): Predicate\Set;
ConditionalClause::in($identifier, $valueList): Predicate\Set;
ConditionalClause::notIn($identifier, $valueList): Predicate\Set;
ConditionalClause::is($identifier, $value): Predicate\Set;
ConditionalClause::isNot($identifier, $value): Predicate\Set;
ConditionalClause::isNull($identifier): Predicate\Set;
ConditionalClause::isNotNull($identifier): Predicate\Set;
ConditionalClause::isTrue($identifier): Predicate\Set;
ConditionalClause::isFalse($identifier): Predicate\Set;
ConditionalClause::isUnknown($identifier): Predicate\Set;
ConditionalClause::isNotUnknown($identifier): Predicate\Set;
ConditionalClause::like($identifier, $pattern, string $escape = null): Predicate\Set;
ConditionalClause::notLike($identifier, $pattern, string $escape = null): Predicate\Set;
ConditionalClause::equal($identifier, $value): Predicate\Set;
ConditionalClause::eq($identifier, $value): Predicate\Set;
ConditionalClause::notEqual($identifier, $value): Predicate\Set;
ConditionalClause::neq($identifier, $value): Predicate\Set;
ConditionalClause::ne($identifier, $value): Predicate\Set;
ConditionalClause::lessThan($identifier, $value): Predicate\Set;
ConditionalClause::lt($identifier, $value): Predicate\Set;
ConditionalClause::lessThanEqual($identifier, $value): Predicate\Set;
ConditionalClause::lte($identifier, $value): Predicate\Set;
ConditionalClause::greaterThanEqual($identifier, $value): Predicate\Set;
ConditionalClause::gte($identifier, $value): Predicate\Set;
ConditionalClause::greaterThan($identifier, $value): Predicate\Set;
ConditionalClause::gt($identifier, $value): Predicate\Set;
ConditionalClause::and(): Predicate\Set;
ConditionalClause::or(): Predicate\Set;
ConditionalClause::beginGroup(string $defaultLogicalOperator = Sql::AND): Predicate\Set;
An endGroup() method is not provided as we call it from the search-condition Predicate\Set context
Examples:
use pine3ree\Db\Sql;
use pine3ree\Db\Sql\Clause\Where;
use pine3ree\Db\Sql\Predicate;
use pine3ree\Db\Sql\Statement\Select;
$date = '2023-10-07';
$select = Sql::select();
$select
    ->from('tax_rate', 'tr')
    ->where // changed context to the composed Where instance
        ->lte('tr.date_min', $date) // changed context to the composed Predicate\Set instance
        ->and()
        ->beginGroup() // changed context to the nested Predicate\Set instance
            ->equal('tr.date_max', '0000-00-00')
            ->or()
            ->gte('tr.date_max', $date)
        ->endGroup(); // changed context back to the Where::$searchCondition Predicate\Set instance
// SELECT "tr".* FROM "tax_rate" "tr" WHERE "tr"."date_min" <= :lte1 AND ("tr"."date_max" = :eq1 OR "tr"."date_max" >= :gte1)
$select = Sql::select();
$select
    ->columns([
        'id',
        'name',
        'originalPrice' => 'price',
    ])
    ->column(Sql::literal('(p.price - p.discount)'), 'discountedPrice')
    ->from('product', 'p')
    ->where
        ->gt('discount', 0.0)
    ->top() // Back to the Select instance, we could have called ->up()->up(), or ->closest(Select::class)
    ->having
        ->lte('discountedPrice', 100.00);
// SELECT "p"."id", "p"."name", "p"."price" AS "originalPrice", ("p".price - "p".discount) AS "discountedPrice"
// FROM "product" "p"
// WHERE "discount" > :gt1
// HAVING "discountedPrice" <= :lte1
The Join clause
The class pine3ree\Db\Sql\Clause\Join abstract the SQL JOIN clause.
A Join instance is created with at least 2 parameters:
- the join type ('', 'INNER', 'CROSS', 'LEFT', 'RIGHT', 'STRAIGHT', 'NATURAL',
  'NATURAL LEFT', 'NATURAL RIGHT' - 
Sql::JOIN_*constants ara available) - the joined table name
 
and most commonly with the following optional parameters
- the joined table alias
 - the join specification in the form of:
 - a sql literal predicate rendered as is,
 - a sql identifier that is automatically wrapped in a
    
USING("identifier")clause, - an 
Onclause or conditions in various form (strings, arrays, predicates, predicate-sets, ..) the will be used to build anOnconditional-clause instance 
Examples:
use pine3ree\Db\Sql;
use pine3ree\Db\Sql\Clause\Join;
use pine3ree\Db\Sql\Predicate;
use pine3ree\Db\Sql\Statement\Select;
$select = new Select(); // or $select = Sql::select()
$select
    ->columns([
        'title',
        'summary',
        'date',
        'author' => 'u.name', // key:alias, value: column
    ])
    ->from('post', 'p')
    ->addJoin(new Join(
        Sql::JOIN_LEFT, // or just "LEFT",
        'user',
        'u',
        'u.id = p.user_id' // Will be used as a literal predicate for the On clause
    ));
// The resulting sql-string is split into two lines to improve readability
//
// SELECT "p"."title", "p"."summary", "p"."date", "u"."name" AS "author" FROM "post" "p"
// LEFT JOIN "user" "u" ON ("u".id = "p".user_id)
// If using a literal predicate then "ON" sql keyword must be included manually, i.e:
new Predicate\Literal('ON u.id = p.user_id')
You will usually call join select method intead of programmatically creating new
Join instances
use pine3ree\Db\Sql;
use pine3ree\Db\Sql\Clause\Join;
use pine3ree\Db\Sql\Statement\Select;
$select = Sql::select()
    ->columns([
        '*',
        'author' => 'u.name',
    ])
    ->from('post', 'p')
    ->innerJoin('user', 'u', [ // conditions array used to build the On clause
        'u.id = p.user_id', // literal string
        'u.enabled' => true, // equality condition in key => value form
    ]);
// SELECT "p".*, "u"."name" AS "author"
// FROM "post" "p"
// INNER JOIN "user" "u" ON ("u".id = "p".user_id AND "u"."enabled" = :eq1)
// When the local and related column names are the same (e.g post_id) we can use
// a sql identifier to trigger the compilation of a USING clause, as in the
// following example:
$select = Sql::select()
    ->columns([
        'post_id',
        'title',
        'review' => 'r.content',
    ])
    ->from('post', 'p')
    ->leftJoin('review', 'r', Sql::identifier('post_id'));
// SELECT "p"."post_id", "p"."title", "r"."content" AS "review"
// FROM "post" "p"
// LEFT JOIN "review" "r" USING("post_id")
The sql Select statement class provides the following utility methods for sql-joins:
Select::addJoin(Join $join): self;
/**
 * Common signature
 *
 * @param string $table The joined table name
 * @param string $alias The joined table alias
 * @param On|Predicate|Predicate\Set|array|string|Literal|Identifier|null $specification
 * @return $this Fluent interface
 */
Select::innerJoin(string $table, string $alias, $specification = null): self;
Select::leftJoin(string $table, string $alias, $specification = null): self;
Select::rightJoin(string $table, string $alias, $specification = null): self;
Select::naturalJoin(string $table, string $alias, $specification = null): self;
Select::naturalLeftJoin(string $table, string $alias, $specification = null): self;
Select::naturalRightJoin(string $table, string $alias, $specification = null): self;
Select::crossJoin(string $table, string $alias, $specification = null): self;
Select::straightJoin(string $table, string $alias, $specification = null): self;