From a3391248e46bbc389dc1880f7ae50aa5dade8731 Mon Sep 17 00:00:00 2001
From: Joas Schilling <nickvergessen@owncloud.com>
Date: Tue, 8 Dec 2015 09:49:21 +0100
Subject: [PATCH] Add select distinct to the query builder

---
 lib/private/db/querybuilder/querybuilder.php  | 22 ++++++++++++
 lib/public/db/querybuilder/iquerybuilder.php  | 16 +++++++++
 .../lib/db/querybuilder/querybuildertest.php  | 36 ++++++++++++++++---
 3 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/lib/private/db/querybuilder/querybuilder.php b/lib/private/db/querybuilder/querybuilder.php
index e70733b5509..b874f5c9911 100644
--- a/lib/private/db/querybuilder/querybuilder.php
+++ b/lib/private/db/querybuilder/querybuilder.php
@@ -324,6 +324,28 @@ class QueryBuilder implements IQueryBuilder {
 		return $this;
 	}
 
+	/**
+	 * Specifies an item that is to be returned uniquely in the query result.
+	 *
+	 * <code>
+	 *     $qb = $conn->getQueryBuilder()
+	 *         ->selectDistinct('type')
+	 *         ->from('users');
+	 * </code>
+	 *
+	 * @param mixed $select The selection expressions.
+	 *
+	 * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+	 */
+	public function selectDistinct($select) {
+
+		$this->queryBuilder->addSelect(
+			'DISTINCT ' . $this->helper->quoteColumnName($select)
+		);
+
+		return $this;
+	}
+
 	/**
 	 * Adds an item that is to be returned in the query result.
 	 *
diff --git a/lib/public/db/querybuilder/iquerybuilder.php b/lib/public/db/querybuilder/iquerybuilder.php
index e3105cf134e..1ff1077d53f 100644
--- a/lib/public/db/querybuilder/iquerybuilder.php
+++ b/lib/public/db/querybuilder/iquerybuilder.php
@@ -256,6 +256,22 @@ interface IQueryBuilder {
 	 */
 	public function selectAlias($select, $alias);
 
+	/**
+	 * Specifies an item that is to be returned uniquely in the query result.
+	 *
+	 * <code>
+	 *     $qb = $conn->getQueryBuilder()
+	 *         ->selectDistinct('type')
+	 *         ->from('users');
+	 * </code>
+	 *
+	 * @param mixed $select The selection expressions.
+	 *
+	 * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+	 * @since 9.0.0
+	 */
+	public function selectDistinct($select);
+
 	/**
 	 * Adds an item that is to be returned in the query result.
 	 *
diff --git a/tests/lib/db/querybuilder/querybuildertest.php b/tests/lib/db/querybuilder/querybuildertest.php
index 828a860ee80..b52fbd7c283 100644
--- a/tests/lib/db/querybuilder/querybuildertest.php
+++ b/tests/lib/db/querybuilder/querybuildertest.php
@@ -48,12 +48,12 @@ class QueryBuilderTest extends \Test\TestCase {
 		$this->queryBuilder = new QueryBuilder($this->connection);
 	}
 
-	protected function createTestingRows() {
+	protected function createTestingRows($appId = 'testFirstResult') {
 		$qB = $this->connection->getQueryBuilder();
 		for ($i = 1; $i < 10; $i++) {
 			$qB->insert('*PREFIX*appconfig')
 				->values([
-					'appid' => $qB->expr()->literal('testFirstResult'),
+					'appid' => $qB->expr()->literal($appId),
 					'configkey' => $qB->expr()->literal('testing' . $i),
 					'configvalue' => $qB->expr()->literal(100 - $i),
 				])
@@ -80,11 +80,11 @@ class QueryBuilderTest extends \Test\TestCase {
 		return $rows;
 	}
 
-	protected function deleteTestingRows() {
+	protected function deleteTestingRows($appId = 'testFirstResult') {
 		$qB = $this->connection->getQueryBuilder();
 
 		$qB->delete('*PREFIX*appconfig')
-			->where($qB->expr()->eq('appid', $qB->expr()->literal('testFirstResult')))
+			->where($qB->expr()->eq('appid', $qB->expr()->literal($appId)))
 			->execute();
 	}
 
@@ -272,6 +272,34 @@ class QueryBuilderTest extends \Test\TestCase {
 		$this->deleteTestingRows();
 	}
 
+	public function testSelectDistinct() {
+		$this->deleteTestingRows('testFirstResult1');
+		$this->deleteTestingRows('testFirstResult2');
+		$this->createTestingRows('testFirstResult1');
+		$this->createTestingRows('testFirstResult2');
+
+		$this->queryBuilder->selectDistinct('appid');
+
+		$this->queryBuilder->from('*PREFIX*appconfig')
+			->where($this->queryBuilder->expr()->in(
+				'appid',
+				[$this->queryBuilder->expr()->literal('testFirstResult1'), $this->queryBuilder->expr()->literal('testFirstResult2')]
+			))
+			->orderBy('appid', 'DESC');
+
+		$query = $this->queryBuilder->execute();
+		$rows = $query->fetchAll();
+		$query->closeCursor();
+
+		$this->assertEquals(
+			[['appid' => 'testFirstResult2'], ['appid' => 'testFirstResult1']],
+			$rows
+		);
+
+		$this->deleteTestingRows('testFirstResult1');
+		$this->deleteTestingRows('testFirstResult2');
+	}
+
 	public function dataAddSelect() {
 		$queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection());
 		return [
-- 
GitLab