Skip to content

Commit

Permalink
feat: add join support for delete and update queries with alias handl…
Browse files Browse the repository at this point in the history
…ing (#411)

* feat: add join support for delete and update queries with alias handling

* tets: remove comment
  • Loading branch information
SonyPradana authored Jan 6, 2025
1 parent 107ce4f commit 6ce2aa2
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 11 deletions.
56 changes: 53 additions & 3 deletions src/System/Database/MyQuery/Delete.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace System\Database\MyQuery;

use System\Database\MyPDO;
use System\Database\MyQuery\Join\AbstractJoin;
use System\Database\MyQuery\Traits\ConditionTrait;
use System\Database\MyQuery\Traits\SubQueryTrait;

Expand All @@ -13,6 +14,8 @@ class Delete extends Execute
use ConditionTrait;
use SubQueryTrait;

protected ?string $alias = null;

public function __construct(string $table_name, MyPDO $PDO)
{
$this->_table = $table_name;
Expand All @@ -24,12 +27,59 @@ public function __toString()
return $this->builder();
}

/**
* Set alias for the table.
* If using an alias, conditions with binding values will be ignored,
* except when using subqueries, clause in join also will be generate as alias.
*/
public function alias(string $alias): self
{
$this->alias = $alias;

return $this;
}

/**
* Join statment:
* - inner join
* - left join
* - right join
* - full join.
*/
public function join(AbstractJoin $ref_table): self
{
$table = $this->alias ?? $this->_table;
$ref_table->table($table);

$this->_join[] = $ref_table->stringJoin();
$binds = (fn () => $this->{'sub_query'})->call($ref_table);

if (null !== $binds) {
$this->_binds = array_merge($this->_binds, $binds->getBind());
}

return $this;
}

private function getJoin(): string
{
return 0 === count($this->_join)
? ''
: implode(' ', $this->_join)
;
}

protected function builder(): string
{
$where = $this->getWhere();
$build = [];

$build['join'] = $this->getJoin();
$build['where'] = $this->getWhere();

$this->_query = "DELETE FROM {$this->_table} {$where}";
$query_parts = implode(' ', array_filter($build, fn ($item) => $item !== ''));

return $this->_query;
return $this->_query = null === $this->alias
? "DELETE FROM {$this->_table} {$query_parts}"
: "DELETE {$this->alias} FROM {$this->_table} AS {$this->alias} {$query_parts}";
}
}
5 changes: 4 additions & 1 deletion src/System/Database/MyQuery/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,11 @@ protected function splitFilters(array $filters): string
foreach ($filters['filters'] as $fieldName => $fieldValue) {
$value = $fieldValue['value'];
$comparation = $fieldValue['comparation'];
$column = str_contains($fieldName, '.') ? $fieldName : "{$table_name}.{$fieldName}";
$bind = $fieldValue['bind'];

if ($value !== '') {
$query[] = "({$table_name}.{$fieldName} {$comparation} :{$fieldName})";
$query[] = "({$column} {$comparation} :{$bind})";
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/System/Database/MyQuery/Traits/ConditionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,12 @@ public function in(string $column_name, $value)
*/
public function compare(string $bind, string $comparation, $value, bool $bindValue = false)
{
$this->_binds[] = Bind::set($bind, $value);
$escape_bind = str_replace('.', '__', $bind);
$this->_binds[] = Bind::set($escape_bind, $value);
$this->_filters[$bind] = [
'value' => $value,
'comparation' => $comparation,
'bind' => $escape_bind,
$bindValue,
];

Expand Down
43 changes: 37 additions & 6 deletions src/System/Database/MyQuery/Update.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace System\Database\MyQuery;

use System\Database\MyPDO;
use System\Database\MyQuery\Join\AbstractJoin;
use System\Database\MyQuery\Traits\ConditionTrait;
use System\Database\MyQuery\Traits\SubQueryTrait;

Expand Down Expand Up @@ -55,22 +56,52 @@ public function value(string $bind, $value)
return $this;
}

protected function builder(): string
/**
* Join statment:
* - inner join
* - left join
* - right join
* - full join.
*/
public function join(AbstractJoin $ref_table): self
{
// overide master table
$ref_table->table($this->_table);

$this->_join[] = $ref_table->stringJoin();
$binds = (fn () => $this->{'sub_query'})->call($ref_table);

if (null !== $binds) {
$this->_binds = array_merge($this->_binds, $binds->getBind());
}

return $this;
}

private function getJoin(): string
{
$where = $this->getWhere();
return 0 === count($this->_join)
? ''
: implode(' ', $this->_join)
;
}

protected function builder(): string
{
$setter = [];
foreach ($this->_binds as $bind) {
if ($bind->hasColumName()) {
$setter[] = $bind->getColumnName() . ' = ' . $bind->getBind();
}
}

// $binds = array_filter($setter);
$set_string = implode(', ', $setter);
$build = [];
$build['join'] = $this->getJoin();
$build[] = 'SET ' . implode(', ', $setter);
$build['where'] = $this->getWhere();

$this->_query = "UPDATE $this->_table SET $set_string $where";
$query_parts = implode(' ', array_filter($build, fn ($item) => $item !== ''));

return $this->_query;
return $this->_query = "UPDATE {$this->_table} {$query_parts}";
}
}
42 changes: 42 additions & 0 deletions tests/DataBase/Query/JoinTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,46 @@ public function itCanGenerateInnerJoinWithSubQuery()
$join->queryBind()
);
}

/** @test */
public function itCanGenerateInnerJoinInDeleteClausa()
{
$join = MyQuery::from('base_table', $this->PDO)
->delete()
->alias('bt')
->join(InnerJoin::ref('join_table', 'base_id', 'join_id'))
->equal('join_table.a', 1)
;

$this->assertEquals(
'DELETE bt FROM base_table AS bt INNER JOIN join_table ON bt.base_id = join_table.join_id WHERE ( (join_table.a = :join_table__a) )',
$join->__toString()
);

$this->assertEquals(
'DELETE bt FROM base_table AS bt INNER JOIN join_table ON bt.base_id = join_table.join_id WHERE ( (join_table.a = 1) )',
$join->queryBind()
);
}

/** @test */
public function itCanGenerateInnerJoinInUpdateClausa()
{
$update = MyQuery::from('test', $this->PDO)
->update()
->value('a', 'b')
->join(InnerJoin::ref('join_table', 'base_id', 'join_id'))
->equal('test.column_1', 100)
;

$this->assertEquals(
'UPDATE test INNER JOIN join_table ON test.base_id = join_table.join_id SET a = :bind_a WHERE ( (test.column_1 = :test__column_1) )',
$update->__toString()
);

$this->assertEquals(
'UPDATE test INNER JOIN join_table ON test.base_id = join_table.join_id SET a = \'b\' WHERE ( (test.column_1 = 100) )',
$update->queryBind()
);
}
}
Loading

0 comments on commit 6ce2aa2

Please sign in to comment.