ENH Enable allowing collisions for field statements

This commit is contained in:
Guy Sartorelli 2023-09-21 15:54:35 +12:00
parent b8665a70d5
commit 2c8cd20b95
No known key found for this signature in database
GPG Key ID: F313E3B9504D496A
2 changed files with 58 additions and 1 deletions

View File

@ -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.
*
@ -287,6 +292,7 @@ class DataQuery
if ($this->collidingFields) {
foreach ($this->collidingFields as $collisionField => $collisions) {
$caseClauses = [];
$lastClauses = [];
foreach ($collisions as $collision) {
if (preg_match('/^"(?<table>[^"]+)"\./', $collision ?? '', $matches)) {
$collisionTable = $matches['table'];
@ -298,9 +304,14 @@ class DataQuery
$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);
}
}
@ -1358,6 +1369,25 @@ class DataQuery
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

View File

@ -172,6 +172,33 @@ class DataQueryTest extends SapphireTest
$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);