Skip to content

Commit

Permalink
ENH Enable allowing collisions for field statements
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Sep 21, 2023
1 parent b8665a7 commit 2c8cd20
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
32 changes: 31 additions & 1 deletion src/ORM/DataQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ class DataQuery
*/
protected $collidingFields = [];

/**
* If true, collisions are allowed for statements aliased as db columns
*/
private $allowCollidingFieldStatements = false;

/**
* Allows custom callback to be registered before getFinalisedQuery is called.
*
Expand Down Expand Up @@ -287,6 +292,7 @@ public function getFinalisedQuery($queriedColumns = null)
if ($this->collidingFields) {
foreach ($this->collidingFields as $collisionField => $collisions) {
$caseClauses = [];
$lastClauses = [];
foreach ($collisions as $collision) {
if (preg_match('/^"(?<table>[^"]+)"\./', $collision ?? '', $matches)) {
$collisionTable = $matches['table'];
Expand All @@ -298,9 +304,14 @@ public function getFinalisedQuery($queriedColumns = null)
$caseClauses[] = "WHEN {$collisionClassColumn} IN ({$collisionClassesSQL}) THEN $collision";
}
} else {
user_error("Bad collision item '$collision'", E_USER_WARNING);
if ($this->getAllowCollidingFieldStatements()) {
$lastClauses[] = "WHEN $collision IS NOT NULL THEN $collision";
} else {
user_error("Bad collision item '$collision'", E_USER_WARNING);
}
}
}
$caseClauses = array_merge($caseClauses, $lastClauses);
$query->selectField("CASE " . implode(" ", $caseClauses) . " ELSE NULL END", $collisionField);
}
}
Expand Down Expand Up @@ -1358,6 +1369,25 @@ public function pushQueryManipulator(DataQueryManipulator $manipulator)
return $this;
}

/**
* Get whether field statements aliased as columns are allowed when that column is already
* being selected
*/
public function getAllowCollidingFieldStatements(): bool
{
return $this->allowCollidingFieldStatements;
}

/**
* Set whether field statements aliased as columns are allowed when that column is already
* being selected
*/
public function setAllowCollidingFieldStatements(bool $value): static
{
$this->allowCollidingFieldStatements = $value;
return $this;
}

private function validateColumnField($field, SQLSelect $query)
{
// standard column - nothing to process here
Expand Down
27 changes: 27 additions & 0 deletions tests/php/ORM/DataQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,33 @@ public function testRelationOrderWithCustomJoin()
$this->assertTrue(true);
}

public function provideFieldCollision()
{
return [
'allow collisions' => [true],
'disallow collisions' => [false],
];
}

/**
* @dataProvider provideFieldCollision
*/
public function testFieldCollision($allowCollisions)
{
$dataQuery = new DataQuery(DataQueryTest\ObjectB::class);
$dataQuery->selectField('COALESCE(NULL, 1) AS "Title"');
$dataQuery->setAllowCollidingFieldStatements($allowCollisions);

if ($allowCollisions) {
$this->assertSQLContains('THEN "DataQueryTest_B"."Title" WHEN COALESCE(NULL, 1) AS "Title" IS NOT NULL THEN COALESCE(NULL, 1) AS "Title" ELSE NULL END AS "Title"', $dataQuery->sql());
} else {
$this->expectError();
$this->expectErrorMessageMatches('/^Bad collision item /');
}

$dataQuery->getFinalisedQuery();
}

public function testDisjunctiveGroup()
{
$dq = new DataQuery(DataQueryTest\ObjectA::class);
Expand Down

0 comments on commit 2c8cd20

Please sign in to comment.