2024-07-21 01:47:21 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
|
|
|
* @license MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2024-06-08 23:58:45 +00:00
|
|
|
|
|
|
|
namespace BitBadger\PDODocument;
|
|
|
|
|
2024-07-21 01:47:21 +00:00
|
|
|
use Exception;
|
|
|
|
|
2024-06-08 23:58:45 +00:00
|
|
|
/**
|
|
|
|
* Criteria for a field WHERE clause
|
|
|
|
*/
|
|
|
|
class Field
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* NOTE: Use static construction methods rather than using this directly; different properties are required
|
|
|
|
* depending on the operation being performed. This is only public so it can be tested.
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field
|
|
|
|
* @param Op $op The operation by which the field will be compared
|
|
|
|
* @param mixed $value The value of the field
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound
|
|
|
|
* @param string $qualifier A table qualifier for the `data` column
|
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public function __construct(public string $fieldName = '', public Op $op = Op::Equal, public mixed $value = '',
|
2024-06-08 23:58:45 +00:00
|
|
|
public string $paramName = '', public string $qualifier = '') { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append the parameter name and value to the given associative array
|
|
|
|
*
|
2024-08-30 13:24:25 +00:00
|
|
|
* @param array<string, mixed> $existing The existing parameters
|
|
|
|
* @return array<string, mixed> The given parameter array with this field's name and value(s) appended
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
|
|
|
public function appendParameter(array $existing): array
|
|
|
|
{
|
|
|
|
switch ($this->op) {
|
2024-09-21 00:29:47 +00:00
|
|
|
case Op::Exists:
|
|
|
|
case Op::NotExists:
|
2024-06-08 23:58:45 +00:00
|
|
|
break;
|
2024-09-21 00:29:47 +00:00
|
|
|
case Op::Between:
|
2024-06-08 23:58:45 +00:00
|
|
|
$existing["{$this->paramName}min"] = $this->value[0];
|
|
|
|
$existing["{$this->paramName}max"] = $this->value[1];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$existing[$this->paramName] = $this->value;
|
|
|
|
}
|
|
|
|
return $existing;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the WHERE clause fragment for this parameter
|
|
|
|
*
|
|
|
|
* @return string The WHERE clause fragment for this parameter
|
2024-07-21 01:47:21 +00:00
|
|
|
* @throws Exception|DocumentException If the database mode has not been set
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
|
|
|
public function toWhere(): string
|
|
|
|
{
|
2024-07-21 01:47:21 +00:00
|
|
|
$mode = Configuration::mode('make field WHERE clause');
|
|
|
|
$fieldName = (empty($this->qualifier) ? '' : "$this->qualifier.") . 'data' . match (true) {
|
2024-06-21 13:46:41 +00:00
|
|
|
!str_contains($this->fieldName, '.') => "->>'$this->fieldName'",
|
2024-07-21 01:47:21 +00:00
|
|
|
$mode === Mode::PgSQL => "#>>'{" . implode(',', explode('.', $this->fieldName)) . "}'",
|
2024-07-22 02:02:16 +00:00
|
|
|
$mode === Mode::SQLite => "->>'" . implode("'->>'", explode('.', $this->fieldName)) . "'",
|
2024-06-21 13:46:41 +00:00
|
|
|
};
|
2024-07-21 01:47:21 +00:00
|
|
|
$fieldPath = match ($mode) {
|
2024-06-21 13:46:41 +00:00
|
|
|
Mode::PgSQL => match (true) {
|
2024-09-21 00:29:47 +00:00
|
|
|
$this->op === Op::Between => is_numeric($this->value[0]) ? "($fieldName)::numeric" : $fieldName,
|
|
|
|
is_numeric($this->value) => "($fieldName)::numeric",
|
|
|
|
default => $fieldName,
|
2024-06-21 13:46:41 +00:00
|
|
|
},
|
2024-07-22 02:02:16 +00:00
|
|
|
default => $fieldName,
|
2024-06-21 13:46:41 +00:00
|
|
|
};
|
2024-06-08 23:58:45 +00:00
|
|
|
$criteria = match ($this->op) {
|
2024-09-21 00:29:47 +00:00
|
|
|
Op::Exists, Op::NotExists => '',
|
|
|
|
Op::Between => " {$this->paramName}min AND {$this->paramName}max",
|
|
|
|
Op::In => "TODO",
|
|
|
|
default => " $this->paramName",
|
2024-06-08 23:58:45 +00:00
|
|
|
};
|
2024-07-21 01:47:21 +00:00
|
|
|
return $fieldPath . ' ' . $this->op->toSQL() . $criteria;
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an equals (=) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for which equality will be checked
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function equal(string $fieldName, mixed $value, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::Equal, $value, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an equals (=) field criterion _(alias for `Field.equal`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for which equality will be checked
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function EQ(string $fieldName, mixed $value, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::equal($fieldName, $value, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a greater than (>) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the greater than comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function greater(string $fieldName, mixed $value, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::Greater, $value, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a greater than (>) field criterion _(alias for `Field.greater`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the greater than comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function GT(string $fieldName, mixed $value, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::greater($fieldName, $value, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a greater than or equal to (>=) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the greater than or equal to comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function greaterOrEqual(string $fieldName, mixed $value, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::GreaterOrEqual, $value, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a greater than or equal to (>=) field criterion _(alias for `Field.greaterOrEqual`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the greater than or equal to comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function GE(string $fieldName, mixed $value, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::greaterOrEqual($fieldName, $value, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a less than (<) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the less than comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function less(string $fieldName, mixed $value, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::Less, $value, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a less than (<) field criterion _(alias for `Field.less`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the less than comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function LT(string $fieldName, mixed $value, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::less($fieldName, $value, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a less than or equal to (<=) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the less than or equal to comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function lessOrEqual(string $fieldName, mixed $value, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::LessOrEqual, $value, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a less than or equal to (<=) field criterion _(alias for `Field.lessOrEqual`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the less than or equal to comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function LE(string $fieldName, mixed $value, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::lessOrEqual($fieldName, $value, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a not equals (<>) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the not equals comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function notEqual(string $fieldName, mixed $value, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::NotEqual, $value, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a not equals (<>) field criterion _(alias for `Field.notEqual`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $value The value for the not equals comparison
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function NE(string $fieldName, mixed $value, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::notEqual($fieldName, $value, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a BETWEEN field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $minValue The lower value for range
|
|
|
|
* @param mixed $maxValue The upper value for the range
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function between(string $fieldName, mixed $minValue, mixed $maxValue, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::Between, [$minValue, $maxValue], $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a BETWEEN field criterion _(alias for `Field.between`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the value will be compared
|
|
|
|
* @param mixed $minValue The lower value for range
|
|
|
|
* @param mixed $maxValue The upper value for the range
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function BT(string $fieldName, mixed $minValue, mixed $maxValue, string $paramName = ''): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::between($fieldName, $minValue, $maxValue, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an IN field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the values will be compared
|
|
|
|
* @param mixed[] $values The potential matching values for the field
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
|
|
|
public static function in(string $fieldName, array $values, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::In, $values, $paramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an IN ARRAY field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field against which the values will be compared
|
|
|
|
* @param mixed[] $values The potential matching values for the field
|
|
|
|
* @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank)
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
|
|
|
public static function inArray(string $fieldName, array $values, string $paramName = ''): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::InArray, $values, $paramName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an exists (IS NOT NULL) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field for which existence will be checked
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function exists(string $fieldName): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::Exists, '', '');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an exists (IS NOT NULL) field criterion _(alias for `Field.exists`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field for which existence will be checked
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function EX(string $fieldName): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::exists($fieldName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a not exists (IS NULL) field criterion
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field for which non-existence will be checked
|
2024-08-30 13:24:25 +00:00
|
|
|
* @return self The field with the requested criterion
|
2024-06-08 23:58:45 +00:00
|
|
|
*/
|
2024-09-21 00:29:47 +00:00
|
|
|
public static function notExists(string $fieldName): self
|
|
|
|
{
|
|
|
|
return new self($fieldName, Op::NotExists, '', '');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a not exists (IS NULL) field criterion _(alias for `Field.notExists`)_
|
|
|
|
*
|
|
|
|
* @param string $fieldName The name of the field for which non-existence will be checked
|
|
|
|
* @return self The field with the requested criterion
|
|
|
|
*/
|
2024-08-30 13:24:25 +00:00
|
|
|
public static function NEX(string $fieldName): self
|
2024-06-08 23:58:45 +00:00
|
|
|
{
|
2024-09-21 00:29:47 +00:00
|
|
|
return self::notExists($fieldName);
|
2024-06-08 23:58:45 +00:00
|
|
|
}
|
|
|
|
}
|