Skip to content

Commit

Permalink
Added support for having and havingRaw
Browse files Browse the repository at this point in the history
  • Loading branch information
Timo Hund committed Aug 4, 2023
1 parent 7ffd60f commit eb34605
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 13 deletions.
53 changes: 41 additions & 12 deletions src/Builder/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Closure;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Stringable;
use NorbyBaru\AwsTimestream\Concerns\BuildersConcern;
use NorbyBaru\AwsTimestream\Contract\QueryBuilderContract;

Expand Down Expand Up @@ -34,6 +35,7 @@ abstract class Builder implements QueryBuilderContract
protected string $table = '';
protected string $fromQuery = '';
protected string $whereQuery = '';
protected string $havingQuery = '';
protected string $selectStatement = '';
protected string $orderByQuery = '';
protected string $groupByQuery = '';
Expand Down Expand Up @@ -124,41 +126,53 @@ public function whereRaw(string $statement): self
public function where(string $column, $value, string $operator = '=', string $boolean = 'and', bool $ago = false): self
{
$query = Str::of($this->whereQuery);
$this->whereQuery = $this->modifyQueryPart('WHERE', $query, $column, $value, $operator, $boolean, $ago);

return $this;
}

protected function modifyQueryPart(
string $sqlPart,
Stringable $query,
string $column,
$value,
string $operator = '=',
string $boolean = 'and',
bool $ago = false
): Stringable {
if (!in_array($sqlPart, ['WHERE', 'HAVING'])) {
throw new \InvalidArgumentException(sprintf('Invalid sql part %s', $sqlPart));
}
$value = $value instanceof Closure
// If the value is a Closure, it means the developer is performing an entire
? '(' . call_user_func($value) . ')'
: $value;

if ($query->length() == 0) {
$whereQuery = $query->append(
sprintf('WHERE %s %s %s', $column, $operator, $value)
$queryPart = $query->append(
sprintf($sqlPart . ' %s %s %s', $column, $operator, $value)
);

if ($ago) {
$whereQuery = $query->append(
sprintf('WHERE %s %s ago(%s)', $column, $operator, $value)
$queryPart = $query->append(
sprintf($sqlPart . ' %s %s ago(%s)', $column, $operator, $value)
);
}

$this->whereQuery = $whereQuery;

return $this;
return $queryPart;
}

$whereQuery = $query->append(
$queryPart = $query->append(
sprintf(' %s %s %s %s', mb_strtoupper($boolean), $column, $operator, $value)
);

if ($ago) {
$whereQuery = $query->append(
$queryPart = $query->append(
sprintf(' %s %s %s ago(%s)', mb_strtoupper($boolean), $column, $operator, $value)
);
}

$this->whereQuery = $whereQuery;

return $this;
return $queryPart;
}

public function whereAgo(string $column, $value, string $operator = '=', string $boolean = 'and'): self
Expand Down Expand Up @@ -300,6 +314,21 @@ public function whereNotNull(string|array $columns, $boolean = 'and'): self
return $this->whereNull($columns, $boolean, true);
}

public function havingRaw(string $statement): self
{
$this->havingQuery = $statement;

return $this;
}

public function having(string $column, $value, string $operator = '=', string $boolean = 'and', bool $ago = false): self
{
$query = Str::of($this->havingQuery);
$this->havingQuery = $this->modifyQueryPart('HAVING', $query, $column, $value, $operator, $boolean, $ago);

return $this;
}

public function limitBy(int $limit): self
{
$this->limitByQuery = sprintf('LIMIT %s', $limit);
Expand Down
11 changes: 11 additions & 0 deletions src/Concerns/BuildersConcern.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public function getOrderByQuery(): string
return $this->orderByQuery;
}

public function getHavingQuery(): string
{
return $this->havingQuery;
}

public function getGroupByQuery(): string
{
return $this->groupByQuery;
Expand Down Expand Up @@ -108,6 +113,12 @@ public function getQueryString(): string
->append($this->getGroupByQuery());
}

if ($this->getHavingQuery()) {
$queryString = $queryString
->append(' ')
->append($this->getHavingQuery());
}

if ($this->getOrderByQuery()) {
$queryString = $queryString
->append(' ')
Expand Down
39 changes: 38 additions & 1 deletion tests/Unit/ReaderUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,51 @@ public function test_query_builder_can_use_aliases_in_selects()

public function test_query_builder_can_add_rawWhere()
{
$sql = "SELECT p.name, avg(r.rating) AS avg_rating FROM \"shop\".\"products\" AS p LEFT JOIN \"shop\".\"reviews\" AS r ON p.id = r.product_id WHERE p.name = \"test\" AND avg_rating > 4 ORDER BY time desc LIMIT 10";
$sql = "SELECT p.name, avg(r.rating) AS avg_rating FROM \"shop\".\"products\" AS p LEFT JOIN \"shop\".\"reviews\" AS r ON p.id = r.product_id WHERE p.name = \"test\" AND avg_rating > 4 GROUP BY p.name ORDER BY time desc LIMIT 10";
$queryBuilder = TimestreamBuilder::query()
->select('p.name, avg(r.rating) AS avg_rating')
->from("shop", 'products', 'p')
->leftJoin("shop", 'reviews', 'r', 'p.id = r.product_id')
->whereRaw("WHERE p.name = \"test\"")
->andWhere('avg_rating', 4, '>')
->orderBy('time', 'desc')
->groupBy('p.name')
->limitBy(10);

$this->assertInstanceOf(Builder::class, $queryBuilder);
$this->assertIsString($queryBuilder->getSql());
$this->assertEquals($queryBuilder->getSql(), $sql);
}

public function test_query_build_can_add_having()
{
$sql = "SELECT p.name, avg(r.rating) AS avg_rating FROM \"shop\".\"products\" AS p LEFT JOIN \"shop\".\"reviews\" AS r ON p.id = r.product_id WHERE p.name = \"test\" GROUP BY p.name HAVING avg(r.rating) > 4 ORDER BY time desc LIMIT 10";
$queryBuilder = TimestreamBuilder::query()
->select('p.name, avg(r.rating) AS avg_rating')
->from("shop", 'products', 'p')
->leftJoin("shop", 'reviews', 'r', 'p.id = r.product_id')
->whereRaw("WHERE p.name = \"test\"")
->orderBy('time', 'desc')
->groupBy('p.name')
->having('avg(r.rating)', 4, '>')
->limitBy(10);

$this->assertInstanceOf(Builder::class, $queryBuilder);
$this->assertIsString($queryBuilder->getSql());
$this->assertEquals($queryBuilder->getSql(), $sql);
}

public function test_query_build_can_add_rawhaving()
{
$sql = "SELECT p.name, avg(r.rating) AS avg_rating FROM \"shop\".\"products\" AS p LEFT JOIN \"shop\".\"reviews\" AS r ON p.id = r.product_id WHERE p.name = \"test\" GROUP BY p.name HAVING avg(r.rating) > 4 ORDER BY time desc LIMIT 10";
$queryBuilder = TimestreamBuilder::query()
->select('p.name, avg(r.rating) AS avg_rating')
->from("shop", 'products', 'p')
->leftJoin("shop", 'reviews', 'r', 'p.id = r.product_id')
->whereRaw("WHERE p.name = \"test\"")
->orderBy('time', 'desc')
->groupBy('p.name')
->havingRaw('HAVING avg(r.rating) > 4')
->limitBy(10);

$this->assertInstanceOf(Builder::class, $queryBuilder);
Expand Down

0 comments on commit eb34605

Please sign in to comment.