From 5d5eceaac0fedb014a1740e4cdeea1bbb1512053 Mon Sep 17 00:00:00 2001 From: Andrej Rypo Date: Tue, 26 Nov 2019 10:03:23 +0100 Subject: [PATCH] Add method Selection::havingOr --- src/Database/Table/Selection.php | 58 +++++++--- .../Database/Table/Selection.havingOr().phpt | 106 ++++++++++++++++++ 2 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 tests/Database/Table/Selection.havingOr().phpt diff --git a/src/Database/Table/Selection.php b/src/Database/Table/Selection.php index 9192fabb6..f7c2abcb6 100644 --- a/src/Database/Table/Selection.php +++ b/src/Database/Table/Selection.php @@ -355,23 +355,7 @@ public function whereOr(array $parameters) if (count($parameters) < 2) { return $this->where($parameters); } - $columns = []; - $values = []; - foreach ($parameters as $key => $val) { - if (is_int($key)) { // whereOr(['full condition']) - $columns[] = $val; - } elseif (strpos($key, '?') === false) { // whereOr(['column1' => 1]) - $columns[] = $key . ' ?'; - $values[] = $val; - } else { // whereOr(['column1 > ?' => 1]) - $qNumber = substr_count($key, '?'); - if ($qNumber > 1 && (!is_array($val) || $qNumber !== count($val))) { - throw new Nette\InvalidArgumentException('Argument count does not match placeholder count.'); - } - $columns[] = $key; - $values = array_merge($values, $qNumber > 1 ? $val : [$val]); - } - } + [$columns, $values] = $this->paramsOr($parameters); $columnsString = '(' . implode(') OR (', $columns) . ')'; return $this->where($columnsString, $values); } @@ -442,6 +426,19 @@ public function having(string $having, ...$params) } + /** + * Sets having clause, more calls rewrite old value. + * @param array $parameters ['column1' => 1, 'column2 > ?' => 2, 'full condition'] + * @return static + */ + public function havingOr(array $parameters) + { + [$columns, $values] = $this->paramsOr($parameters); + $columnsString = count($columns) > 1 ? '(' . implode(') OR (', $columns) . ')' : implode('', $columns); + return $this->having($columnsString, $values); + } + + /** * Aliases table. Example ':book:book_tag.tag', 'tg' * @return static @@ -756,6 +753,33 @@ public function getDataRefreshed(): bool } + /** + * @param array $parameters ['column1' => 1, 'column2 > ?' => 2, 'full condition'] + * @return array [$columns, $values] to be used with `where` or `having` + */ + protected function paramsOr(array $parameters): array + { + $columns = []; + $values = []; + foreach ($parameters as $key => $val) { + if (is_int($key)) { // whereOr(['full condition']) + $columns[] = $val; + } elseif (strpos($key, '?') === FALSE) { // whereOr(['column1' => 1]) + $columns[] = $key . ' ?'; + $values[] = $val; + } else { // whereOr(['column1 > ?' => 1]) + $qNumber = substr_count($key, '?'); + if ($qNumber > 1 && (!is_array($val) || $qNumber !== count($val))) { + throw new Nette\InvalidArgumentException('Argument count does not match placeholder count.'); + } + $columns[] = $key; + $values = array_merge($values, $qNumber > 1 ? $val : [$val]); + } + } + return [$columns, $values]; + } + + /********************* manipulation ****************d*g**/ diff --git a/tests/Database/Table/Selection.havingOr().phpt b/tests/Database/Table/Selection.havingOr().phpt new file mode 100644 index 000000000..64ebcd9f1 --- /dev/null +++ b/tests/Database/Table/Selection.havingOr().phpt @@ -0,0 +1,106 @@ +table('book')->havingOr([ + 'author_id' => 12, + 'title' => 'JUSH', + ])->count(); + Assert::same(3, $count); +}); + + +// full condition +test(function () use ($context) { + $count = $context->table('book')->havingOr([ + 'translator_id IS NULL', + 'title' => 'Dibi', + ])->count(); + Assert::same(2, $count); +}); + + +// with question mark +test(function () use ($context) { + $count = $context->table('book')->havingOr([ + 'id > ?' => 3, + 'translator_id' => 11, + ])->count(); + Assert::same(2, $count); +}); + + +// just one condition +test(function () use ($context) { + $count = $context->table('book')->havingOr([ + 'id > ?' => 3, + ])->count(); + Assert::same(1, $count); +}); + + +// with question mark +test(function () use ($context) { + $count = $context->table('book')->havingOr([ + 'id ?' => [3, 4], + 'translator_id' => 11, + ])->count(); + Assert::same(3, $count); +}); + + +// multiple values for one key +test(function () use ($context) { + $count = $context->table('author')->havingOr([ + 'id > ?' => 12, + 'ROUND(id, ?) = ?' => [5, 3], + ])->count(); + Assert::same(1, $count); +}); + + +// nested condition +test(function () use ($context) { + $books = $context->table('book')->havingOr([ + 'id = ?' => 4, + 'author_id = ? AND translator_id ?' => [11, null], + ]); + Assert::same(2, $books->count()); +}); + + +// invalid param count +test(function () use ($context) { + $f = function () use ($context) { + $context->table('author')->havingOr([ + 'id > ?' => 3, + 'ROUND(id, ?) = ?' => [5], + ])->count(); + }; + Assert::throws($f, Nette\InvalidArgumentException::class, 'Argument count does not match placeholder count.'); +}); + + +// invalid param count +test(function () use ($context) { + $f = function () use ($context) { + $context->table('author')->havingOr([ + 'id > ?' => 3, + 'ROUND(id, ?) = ?' => 5, + ])->count(); + }; + Assert::throws($f, Nette\InvalidArgumentException::class, 'Argument count does not match placeholder count.'); +});