Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:
- ./src:/usr/src/code/src
- ./tests:/usr/src/code/tests
- ./phpunit.xml:/usr/src/code/phpunit.xml
- ./vendor/utopia-php/mongo:/usr/src/code/vendor/utopia-php/mongo
ports:
- "8708:8708"

Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
stopOnFailure="true">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>
Expand Down
25 changes: 16 additions & 9 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -1032,14 +1032,11 @@ public function find(string $collection, array $queries = [], ?int $limit = 25,
}
}

foreach ($queries as $query) {
if ($query->getMethod() === Query::TYPE_SELECT) {
continue;
}
$where[] = $this->getSQLCondition($query);
$conditions = $this->getSQLConditions($queries);
if(!empty($conditions)){
$where[] = $conditions;
}


if (Authorization::$status) {
$where[] = $this->getSQLPermissionsCondition($name, $roles);
}
Expand Down Expand Up @@ -1150,8 +1147,9 @@ public function count(string $collection, array $queries = [], ?int $max = null,
$where = [];
$limit = \is_null($max) ? '' : 'LIMIT :max';

foreach ($queries as $query) {
$where[] = $this->getSQLCondition($query);
$conditions = $this->getSQLConditions($queries);
if(!empty($conditions)){
$where[] = $conditions;
}

if (Authorization::$status) {
Expand Down Expand Up @@ -1302,7 +1300,7 @@ protected function getAttributeProjection(array $selections, string $prefix = ''
return \implode(', ', $selections);
}

/*
/**
* Get SQL Condition
*
* @param Query $query
Expand All @@ -1323,6 +1321,15 @@ protected function getSQLCondition(Query $query): string
$placeholder = $this->getSQLPlaceholder($query);

switch ($query->getMethod()) {
case Query::TYPE_OR:
$conditions = [];
/* @var $q Query */
foreach ($query->getValue() as $q){
$conditions[] = $this->getSQLCondition($q);
}

return empty($condition) ? '' : ' OR (' . implode(' AND ', $conditions) . ')';

case Query::TYPE_SEARCH:
return "MATCH(table_main.{$attribute}) AGAINST (:{$placeholder}_0 IN BOOLEAN MODE)";

Expand Down
7 changes: 6 additions & 1 deletion src/Database/Adapter/Mongo.php
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,6 @@ public function find(string $collection, array $queries = [], ?int $limit = 25,

$filters = $this->recursiveReplace($filters, '$', '_', $this->operators);
$filters = $this->timeFilter($filters);

/**
* @var array<Document>
*/
Expand Down Expand Up @@ -1252,6 +1251,11 @@ protected function buildFilters(array $queries): array
continue;
}

if ($query->getMethod() === Query::TYPE_OR) {
$filters['$or'][] = $this->buildFilters($query->getValue());
continue;
}

if ($query->getAttribute() === '$id') {
$query->setAttribute('_uid');
} elseif ($query->getAttribute() === '$internalId') {
Expand Down Expand Up @@ -1326,6 +1330,7 @@ protected function getQueryOperator(string $operator): string
Query::TYPE_BETWEEN => 'between',
Query::TYPE_STARTS_WITH,
Query::TYPE_ENDS_WITH => '$regex',
Query::TYPE_OR => '$or',
default => throw new DatabaseException('Unknown operator:' . $operator . '. Must be one of ' . Query::TYPE_EQUAL . ', ' . Query::TYPE_NOT_EQUAL . ', ' . Query::TYPE_LESSER . ', ' . Query::TYPE_LESSER_EQUAL . ', ' . Query::TYPE_GREATER . ', ' . Query::TYPE_GREATER_EQUAL . ', ' . Query::TYPE_IS_NULL . ', ' . Query::TYPE_IS_NOT_NULL . ', ' . Query::TYPE_BETWEEN . ', ' . Query::TYPE_CONTAINS . ', ' . Query::TYPE_SEARCH . ', ' . Query::TYPE_SELECT),
};
}
Expand Down
16 changes: 7 additions & 9 deletions src/Database/Adapter/Postgres.php
Original file line number Diff line number Diff line change
Expand Up @@ -1039,14 +1039,11 @@ public function find(string $collection, array $queries = [], ?int $limit = 25,
}
}

foreach ($queries as $query) {
if ($query->getMethod() === Query::TYPE_SELECT) {
continue;
}
$where[] = $this->getSQLCondition($query);
$conditions = $this->getSQLConditions($queries);
if(!empty($conditions)){
$where[] = $conditions;
}


if (Authorization::$status) {
$where[] = $this->getSQLPermissionsCondition($name, $roles);
}
Expand Down Expand Up @@ -1157,10 +1154,11 @@ public function count(string $collection, array $queries = [], ?int $max = null,
$where = [];
$limit = \is_null($max) ? '' : 'LIMIT :max';

foreach ($queries as $query) {
$where[] = $this->getSQLCondition($query);
$conditions = $this->getSQLConditions($queries);
if(!empty($conditions)){
$where[] = $conditions;
}

if (Authorization::$status) {
$where[] = $this->getSQLPermissionsCondition($name, $roles);
}
Expand Down
55 changes: 54 additions & 1 deletion src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,13 @@ protected function bindConditionValue(mixed $stmt, Query $query): void
return;
}

if($query->getMethod() === Query::TYPE_OR){
foreach ($query->getValue() as $value) {
$this->bindConditionValue($stmt, $value);
}
return;
}

foreach ($query->getValues() as $key => $value) {
$value = match ($query->getMethod()) {
Query::TYPE_STARTS_WITH => $this->escapeWildcards($value) . '%',
Expand Down Expand Up @@ -926,4 +933,50 @@ public function getMaxIndexLength(): int
{
return 768;
}
}

///**
// * @param $stmt
// * @param Query[] $queries
// * @return void
// */
//public function bindNestedConditionValue($stmt, array $queries = []){
// /** @var PDOStatement $stmt */
// foreach ($queries as $query) {
// if(is_array($query)){
// $this->bindNestedConditionValue($stmt, $query);
// }
// else {
// if ($query->getMethod() === Query::TYPE_SEARCH) continue;
// if ($query->getMethod() === Query::TYPE_OR){
// $this->bindNestedConditionValue($stmt, $query->getValues()); // Nested $queries are in values
// }else {
// foreach ($query->getValues() as $key => $value) {
// $placeholder = $this->getSQLPlaceholder($query).'_'.$key;
// $stmt->bindValue($placeholder, $value, $this->getPDOType($value));
// }
// }
// }
// }}

public function getSQLConditions(array $queries = []): string
{
$separator = 'AND';
$conditions = [];
foreach ($queries as $query) {

if ($query->getMethod() === Query::TYPE_SELECT) {
continue;
}

/* @var $query Query */
if($query->getMethod() === Query::TYPE_OR){
$separator = 'or';
$conditions[] = $this->getSQLConditions($query->getValue());
}
else $conditions[] = $this->getSQLCondition($query);
}

$tmp = implode(' ' . $separator . ' ', $conditions);
return empty($tmp) ? '' : '(' . $tmp . ')';
}
}
2 changes: 2 additions & 0 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -4181,6 +4181,8 @@ public function find(string $collection, array $queries = [], ?int $timeout = nu
}
}

unset($query); // It is used previously as reference

// Remove internal attributes which are not queried
foreach ($queries as $query) {
if ($query->getMethod() === Query::TYPE_SELECT) {
Expand Down
41 changes: 40 additions & 1 deletion src/Database/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class Query
public const TYPE_BETWEEN = 'between';
public const TYPE_STARTS_WITH = 'startsWith';
public const TYPE_ENDS_WITH = 'endsWith';

public const TYPE_SELECT = 'select';
public const TYPE_OR = 'or';

// Order methods
public const TYPE_ORDERDESC = 'orderDesc';
Expand Down Expand Up @@ -178,6 +178,7 @@ public static function isMethod(string $value): bool
self::TYPE_BETWEEN,
self::TYPE_STARTS_WITH,
self::TYPE_ENDS_WITH,
self::TYPE_OR,
self::TYPE_SELECT => true,
default => false,
};
Expand All @@ -192,6 +193,12 @@ public static function isMethod(string $value): bool
*/
public static function parse(string $filter): self
{

if(substr($filter, 0, 3) === 'or('){
var_dump('Found or operation !!!!!!!!!!!');
var_dump($filter);
}

// Init empty vars we fill later
$method = '';
$params = [];
Expand Down Expand Up @@ -363,6 +370,13 @@ public static function parse(string $filter): self
}
return new self($method);

case self::TYPE_OR:
var_dump($method);
var_dump($parsedParams);
var_dump('parsing end ........');
die;
return new self($method);

default:
return new self($method);
}
Expand Down Expand Up @@ -694,6 +708,15 @@ public static function endsWith(string $attribute, string $value): self
return new self(self::TYPE_ENDS_WITH, $attribute, [$value]);
}

/**
* @param array<Query> $queries
* @return static
*/
public static function or(array $queries): self
{
return new self(self::TYPE_OR, '', [$queries]);
}

/**
* Filters $queries for $types
*
Expand Down Expand Up @@ -828,4 +851,20 @@ public static function parseQueries(array $queries): array

return $parsed;
}

/**
* Is isNested
*
* Function will return true if nested method
*
* @return bool
*/
public function isNested(): bool
{
if($this->getMethod() === self::TYPE_OR){
return true;
}

return false;
}
}
1 change: 1 addition & 0 deletions src/Database/Validator/IndexedQueries.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public function isValid($value): bool
return false;
}
$queries = [];

foreach ($value as $query) {
if (!$query instanceof Query) {
$query = Query::parse($query);
Expand Down
24 changes: 23 additions & 1 deletion src/Database/Validator/Queries.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public function isValid($value): bool
return false;
}

$queries = [];

foreach ($value as $query) {
if (!$query instanceof Query) {
try {
Expand All @@ -61,6 +63,14 @@ public function isValid($value): bool
}
}

if($query->isNested()){
if(!self::isValid($query->getValue())){
return false;
}
}

$queries[] = $query;

$method = $query->getMethod();
$methodType = match ($method) {
Query::TYPE_SELECT => Base::METHOD_TYPE_SELECT,
Expand All @@ -82,7 +92,8 @@ public function isValid($value): bool
Query::TYPE_BETWEEN,
Query::TYPE_STARTS_WITH,
Query::TYPE_CONTAINS,
Query::TYPE_ENDS_WITH => Base::METHOD_TYPE_FILTER,
Query::TYPE_ENDS_WITH,
Query::TYPE_OR => Base::METHOD_TYPE_FILTER,
default => '',
};

Expand All @@ -105,6 +116,17 @@ public function isValid($value): bool
}
}

// todo: Is there a better way to assure or does not come first?
// todo: what to do about and nested later on when comes first?
$grouped = Query::groupByType($queries);
$filters = $grouped['filters'];
if(isset($filters[0])){
if ($filters[0]->getMethod() === Query::TYPE_OR) {
$this->message = \ucfirst($filters[0]->getMethod()) . ' query can not come first';
return false;
}
}

return true;
}

Expand Down
Loading