Explorar o código

Fix logic for searching labels (#7863)

`L:1 L:2` is supposed to be an implicit `AND`,
while `L:1,2` as well as `L:1 OR L:2` is an `OR` logic
Alexandre Alapetite hai 7 meses
pai
achega
288992d9ad
Modificáronse 3 ficheiros con 65 adicións e 46 borrados
  1. 38 30
      app/Models/EntryDAO.php
  2. 16 16
      app/Models/Search.php
  3. 11 0
      tests/app/Models/SearchTest.php

+ 38 - 30
app/Models/EntryDAO.php

@@ -937,49 +937,57 @@ SQL;
 			}
 
 			if ($filter->getLabelIds() !== null) {
-				if ($filter->getLabelIds() === '*') {
-					$sub_search .= 'AND EXISTS (SELECT et.id_tag FROM `_entrytag` et WHERE et.id_entry = ' . $alias . 'id) ';
-				} else {
-					$sub_search .= 'AND ' . $alias . 'id IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (';
-					foreach ($filter->getLabelIds() as $label_id) {
-						$sub_search .= '?,';
-						$values[] = $label_id;
+				foreach ($filter->getLabelIds() as $label_ids) {
+					if ($label_ids === '*') {
+						$sub_search .= 'AND EXISTS (SELECT et.id_tag FROM `_entrytag` et WHERE et.id_entry = ' . $alias . 'id) ';
+					} else {
+						$sub_search .= 'AND ' . $alias . 'id IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (';
+						foreach ($label_ids as $label_id) {
+							$sub_search .= '?,';
+							$values[] = $label_id;
+						}
+						$sub_search = rtrim($sub_search, ',');
+						$sub_search .= ')) ';
 					}
-					$sub_search = rtrim($sub_search, ',');
-					$sub_search .= ')) ';
 				}
 			}
 			if ($filter->getNotLabelIds() !== null) {
-				if ($filter->getNotLabelIds() === '*') {
-					$sub_search .= 'AND NOT EXISTS (SELECT et.id_tag FROM `_entrytag` et WHERE et.id_entry = ' . $alias . 'id) ';
-				} else {
-					$sub_search .= 'AND ' . $alias . 'id NOT IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (';
-					foreach ($filter->getNotLabelIds() as $label_id) {
-						$sub_search .= '?,';
-						$values[] = $label_id;
+				foreach ($filter->getNotLabelIds() as $label_ids) {
+					if ($label_ids === '*') {
+						$sub_search .= 'AND NOT EXISTS (SELECT et.id_tag FROM `_entrytag` et WHERE et.id_entry = ' . $alias . 'id) ';
+					} else {
+						$sub_search .= 'AND ' . $alias . 'id NOT IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (';
+						foreach ($label_ids as $label_id) {
+							$sub_search .= '?,';
+							$values[] = $label_id;
+						}
+						$sub_search = rtrim($sub_search, ',');
+						$sub_search .= ')) ';
 					}
-					$sub_search = rtrim($sub_search, ',');
-					$sub_search .= ')) ';
 				}
 			}
 
 			if ($filter->getLabelNames() !== null) {
-				$sub_search .= 'AND ' . $alias . 'id IN (SELECT et.id_entry FROM `_entrytag` et, `_tag` t WHERE et.id_tag = t.id AND t.name IN (';
-				foreach ($filter->getLabelNames() as $label_name) {
-					$sub_search .= '?,';
-					$values[] = $label_name;
+				foreach ($filter->getLabelNames() as $label_names) {
+					$sub_search .= 'AND ' . $alias . 'id IN (SELECT et.id_entry FROM `_entrytag` et, `_tag` t WHERE et.id_tag = t.id AND t.name IN (';
+					foreach ($label_names as $label_name) {
+						$sub_search .= '?,';
+						$values[] = $label_name;
+					}
+					$sub_search = rtrim($sub_search, ',');
+					$sub_search .= ')) ';
 				}
-				$sub_search = rtrim($sub_search, ',');
-				$sub_search .= ')) ';
 			}
 			if ($filter->getNotLabelNames() !== null) {
-				$sub_search .= 'AND ' . $alias . 'id NOT IN (SELECT et.id_entry FROM `_entrytag` et, `_tag` t WHERE et.id_tag = t.id AND t.name IN (';
-				foreach ($filter->getNotLabelNames() as $label_name) {
-					$sub_search .= '?,';
-					$values[] = $label_name;
+				foreach ($filter->getNotLabelNames() as $label_names) {
+					$sub_search .= 'AND ' . $alias . 'id NOT IN (SELECT et.id_entry FROM `_entrytag` et, `_tag` t WHERE et.id_tag = t.id AND t.name IN (';
+					foreach ($label_names as $label_name) {
+						$sub_search .= '?,';
+						$values[] = $label_name;
+					}
+					$sub_search = rtrim($sub_search, ',');
+					$sub_search .= ')) ';
 				}
-				$sub_search = rtrim($sub_search, ',');
-				$sub_search .= ')) ';
 			}
 
 			if ($filter->getAuthor() !== null) {

+ 16 - 16
app/Models/Search.php

@@ -23,9 +23,9 @@ class FreshRSS_Search implements \Stringable {
 	private ?array $feed_ids = null;
 	/** @var list<int>|null */
 	private ?array $category_ids = null;
-	/** @var list<int>|'*'|null */
+	/** @var list<list<int>|'*'>|null */
 	private $label_ids = null;
-	/** @var list<string>|null */
+	/** @var list<list<string>>|null */
 	private ?array $label_names = null;
 	/** @var list<string>|null */
 	private ?array $intitle = null;
@@ -66,9 +66,9 @@ class FreshRSS_Search implements \Stringable {
 	private ?array $not_feed_ids = null;
 	/** @var list<int>|null */
 	private ?array $not_category_ids = null;
-	/** @var list<int>|'*'|null */
+	/** @var list<list<int>|'*'>|null */
 	private $not_label_ids = null;
-	/** @var list<string>|null */
+	/** @var list<list<string>>|null */
 	private ?array $not_label_names = null;
 	/** @var list<string>|null */
 	private ?array $not_intitle = null;
@@ -180,19 +180,19 @@ class FreshRSS_Search implements \Stringable {
 		return $this->not_category_ids;
 	}
 
-	/** @return list<int>|'*'|null */
-	public function getLabelIds(): array|string|null {
+	/** @return list<list<int>|'*'>|null */
+	public function getLabelIds(): array|null {
 		return $this->label_ids;
 	}
-	/** @return list<int>|'*'|null */
-	public function getNotLabelIds(): array|string|null {
+	/** @return list<list<int>|'*'>|null */
+	public function getNotLabelIds(): array|null {
 		return $this->not_label_ids;
 	}
-	/** @return list<string>|null */
+	/** @return list<list<string>>|null */
 	public function getLabelNames(): ?array {
 		return $this->label_names;
 	}
-	/** @return list<string>|null */
+	/** @return list<list<string>>|null */
 	public function getNotLabelNames(): ?array {
 		return $this->not_label_names;
 	}
@@ -481,7 +481,7 @@ class FreshRSS_Search implements \Stringable {
 			$this->label_ids = [];
 			foreach ($ids_lists as $ids_list) {
 				if ($ids_list === '*') {
-					$this->label_ids = '*';
+					$this->label_ids[] = '*';
 					break;
 				}
 				$label_ids = explode(',', $ids_list);
@@ -489,7 +489,7 @@ class FreshRSS_Search implements \Stringable {
 				/** @var list<int> $label_ids */
 				$label_ids = array_map('intval', $label_ids);
 				if (!empty($label_ids)) {
-					$this->label_ids = array_merge($this->label_ids, $label_ids);
+					$this->label_ids[] = $label_ids;
 				}
 			}
 		}
@@ -503,7 +503,7 @@ class FreshRSS_Search implements \Stringable {
 			$this->not_label_ids = [];
 			foreach ($ids_lists as $ids_list) {
 				if ($ids_list === '*') {
-					$this->not_label_ids = '*';
+					$this->not_label_ids[] = '*';
 					break;
 				}
 				$label_ids = explode(',', $ids_list);
@@ -511,7 +511,7 @@ class FreshRSS_Search implements \Stringable {
 				/** @var list<int> $label_ids */
 				$label_ids = array_map('intval', $label_ids);
 				if (!empty($label_ids)) {
-					$this->not_label_ids = array_merge($this->not_label_ids, $label_ids);
+					$this->not_label_ids[] = $label_ids;
 				}
 			}
 		}
@@ -537,7 +537,7 @@ class FreshRSS_Search implements \Stringable {
 				$names_array = explode(',', $names_list);
 				$names_array = self::removeEmptyValues($names_array);
 				if (!empty($names_array)) {
-					$this->label_names = array_merge($this->label_names, $names_array);
+					$this->label_names[] = $names_array;
 				}
 			}
 		}
@@ -563,7 +563,7 @@ class FreshRSS_Search implements \Stringable {
 				$names_array = explode(',', $names_list);
 				$names_array = self::removeEmptyValues($names_array);
 				if (!empty($names_array)) {
-					$this->not_label_names = array_merge($this->not_label_names, $names_array);
+					$this->not_label_names[] = $names_array;
 				}
 			}
 		}

+ 11 - 0
tests/app/Models/SearchTest.php

@@ -505,6 +505,17 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 				'(e.content ~ ? )',
 				['^(ab|cd)']
 			],
+			[
+				'L:1 L:2',
+				'(e.id IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (?)) AND ' .
+					'e.id IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (?)) )',
+				[1, 2]
+			],
+			[
+				'L:1,2',
+				'(e.id IN (SELECT et.id_entry FROM `_entrytag` et WHERE et.id_tag IN (?,?)) )',
+				[1, 2]
+			],
 		];
 	}