From 51728a1284e3f39e9e30c71c5460903a37329b5b Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Wed, 3 Jun 2026 11:15:12 +0530 Subject: [PATCH] feat: add UniqueException for non-_uid unique violations - Add Unique.php exception class (extends Exception) - Add processException override in MariaDB, Postgres, SQLite adapters - Non-_uid unique violations throw UniqueException - _uid duplicates still throw DuplicateException --- src/Database/Adapter/MariaDB.php | 3 ++- src/Database/Adapter/Postgres.php | 11 ++++++++--- src/Database/Adapter/SQLite.php | 3 ++- src/Database/Exception/Unique.php | 9 +++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/Database/Exception/Unique.php diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 599da878e..37c230f60 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -10,6 +10,7 @@ use Utopia\Database\Exception\Character as CharacterException; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; +use Utopia\Database\Exception\Unique as UniqueException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Operator as OperatorException; use Utopia\Database\Exception\Query as QueryException; @@ -1995,7 +1996,7 @@ protected function processException(PDOException $e): \Exception return new DuplicateException('Duplicate permissions for document', $e->getCode(), $e); } if (!\str_contains($message, '_uid')) { - return new DuplicateException('Document with the requested unique attributes already exists', $e->getCode(), $e); + return new UniqueException('Unique index violation', $e->getCode(), $e); } return new DuplicateException('Document already exists', $e->getCode(), $e); } diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index d81cdec0b..85cdfcf1a 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -11,6 +11,7 @@ use Utopia\Database\Exception as DatabaseException; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; +use Utopia\Database\Exception\Unique as UniqueException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Operator as OperatorException; use Utopia\Database\Exception\Timeout as TimeoutException; @@ -2224,9 +2225,13 @@ protected function processException(PDOException $e): \Exception // Duplicate row if ($e->getCode() === '23505' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 7) { - $message = $e->getMessage(); - if (!\str_contains($message, '_uid')) { - return new DuplicateException('Document with the requested unique attributes already exists', $e->getCode(), $e); + if (preg_match('/Key \(([^)]+)\)=\(.+\) already exists/', $e->getMessage(), $matches)) { + $columns = array_map('trim', explode(',', $matches[1])); + sort($columns); + $target = $this->sharedTables ? ['_tenant', '_uid'] : ['_uid']; + if ($columns !== $target) { + return new UniqueException('Unique index violation', $e->getCode(), $e); + } } return new DuplicateException('Document already exists', $e->getCode(), $e); } diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index 5b07ce3b7..952d2858f 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -11,6 +11,7 @@ use Utopia\Database\Exception as DatabaseException; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; +use Utopia\Database\Exception\Unique as UniqueException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Operator as OperatorException; use Utopia\Database\Exception\Timeout as TimeoutException; @@ -1994,7 +1995,7 @@ protected function processException(PDOException $e): \Exception stripos($message, 'duplicate') !== false ) { if (!\str_contains($message, '_uid')) { - return new DuplicateException('Document with the requested unique attributes already exists', $e->getCode(), $e); + return new UniqueException('Unique index violation', $e->getCode(), $e); } return new DuplicateException('Document already exists', $e->getCode(), $e); } diff --git a/src/Database/Exception/Unique.php b/src/Database/Exception/Unique.php new file mode 100644 index 000000000..57a4dc961 --- /dev/null +++ b/src/Database/Exception/Unique.php @@ -0,0 +1,9 @@ +