N°6151 - Allow to select classes on union outside the already selected classes

This commit is contained in:
Eric Espie
2023-05-31 14:40:13 +02:00
parent 31a96d24dd
commit 5f359b2b61
2 changed files with 50 additions and 7 deletions

View File

@@ -224,6 +224,10 @@ class DBUnionSearch extends DBSearch
}
/**
* Set the selected classes for this query.
* The selected classes can be either in the selected classes of all the queries,
* or they should exist in all the sub-queries of the union.
*
* @param array $aSelectedClasses array of aliases
*
* @throws \Exception
@@ -236,22 +240,31 @@ class DBUnionSearch extends DBSearch
$aAliasesToColumn = array_flip(array_keys($oFirstSearch->GetSelectedClasses()));
foreach ($aSelectedClasses as $sSelectedAlias) {
if (!isset($aAliasesToColumn[$sSelectedAlias])) {
throw new CoreException("SetSelectedClasses: Invalid class alias $sSelectedAlias");
// The selected class is not in the selected classes of the union,
// try to delegate the feature to the sub-queries
$aSelectedColumns = [];
break;
}
$aSelectedColumns[] = $aAliasesToColumn[$sSelectedAlias];
}
// 1 - change for each search
foreach ($this->aSearches as $iPos => $oSearch)
{
foreach ($this->aSearches as $iPos => $oSearch) {
$aCurrentSelectedAliases = [];
foreach ($aSelectedColumns as $iColumn) {
$aCurrentSelectedAliases[] = $this->aColumnToAliases[$iColumn][$iPos];
if (count($aSelectedColumns) === 0) {
// Default to the list of aliases given
$aCurrentSelectedAliases = $aSelectedClasses;
} else {
// Map the aliases for each query
foreach ($aSelectedColumns as $iColumn) {
$aCurrentSelectedAliases[] = $this->aColumnToAliases[$iColumn][$iPos];
}
}
// Throws an exception if not valid
$oSearch->SetSelectedClasses($aCurrentSelectedAliases);
}
// 2 - update the lowest common ancestors
$this->ComputeSelectedClasses();
}

View File

@@ -115,9 +115,9 @@ class DBUnionSearchTest extends ItopDataTestCase
{
return [
[
'sSourceOQL' => "SELECT P1, L1 FROM Person AS P1 JOIN Location AS L1 ON P1.location_id = L1.id WHERE L1.id = 1",
'sSourceOQL' => "SELECT P1, L1 FROM Person AS P1 JOIN Location AS L1 ON P1.location_id = L1.id WHERE L1.id = 1",
'sClassAlias' => "L1",
'sFilterOQL' => "SELECT Location AS L2 WHERE L2.id = 2 UNION SELECT Location AS L3 WHERE L3.id = 3",
'sFilterOQL' => "SELECT Location AS L2 WHERE L2.id = 2 UNION SELECT Location AS L3 WHERE L3.id = 3",
'sExpected' => "SELECT `P1`, `L1` FROM Person AS `P1` JOIN Location AS `L1` ON `P1`.location_id = `L1`.id WHERE ((`L1`.`id` = 1) AND (`L1`.`id` = 2)) UNION SELECT `P1`, `L1` FROM Person AS `P1` JOIN Location AS `L1` ON `P1`.location_id = `L1`.id WHERE ((`L1`.`id` = 1) AND (`L1`.`id` = 3))",
],
[
@@ -159,4 +159,34 @@ class DBUnionSearchTest extends ItopDataTestCase
],
];
}
/**
* @dataProvider SetSelectedClassesProvider
* @param $sOQL
* @param $sSelectedClass
*
* @return void
* @throws \CoreException
* @throws \OQLException
*/
public function testSetSelectedClasses(string $sOQL, array $aSelectedClasses, string $sExpectedOQL)
{
$oSearch = DBSearch::FromOQL($sOQL);
$this->debug($oSearch->ToOQL());
$this->debug("Set selected classes to [ ".implode(" ,", $aSelectedClasses)." ]");
$oSearch->SetSelectedClasses($aSelectedClasses);
$this->debug($oSearch->ToOQL());
$this->assertEquals($sExpectedOQL, $oSearch->ToOQL());
}
public function SetSelectedClassesProvider()
{
return [
'N°6151' => [
'OQL' => "SELECT P FROM Person AS P JOIN User AS U ON U.contactid = P.id UNION SELECT P FROM Person AS P JOIN User AS U ON U.contactid = P.id",
'SelectedClasses' => ['U'],
'Expected OQL' => "SELECT `U` FROM Person AS `P` JOIN User AS `U` ON `U`.contactid = `P`.id WHERE 1 UNION SELECT `U` FROM Person AS `P` JOIN User AS `U` ON `U`.contactid = `P`.id WHERE 1",
],
];
}
}