Skip to content

Commit 64b671e

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat-query-lib
# Conflicts: # composer.lock # src/Database/Adapter.php # src/Database/Adapter/MariaDB.php # src/Database/Adapter/Mongo.php # src/Database/Adapter/Pool.php # src/Database/Adapter/Postgres.php # src/Database/Adapter/SQL.php # src/Database/Adapter/SQLite.php # src/Database/Database.php # src/Database/Document.php # src/Database/Mirror.php # src/Database/PDO.php # src/Database/Validator/Operator.php # src/Database/Validator/Query/Filter.php # src/Database/Validator/Sequence.php # src/Database/Validator/Structure.php # tests/e2e/Adapter/Scopes/CollectionTests.php # tests/e2e/Adapter/Scopes/DocumentTests.php # tests/e2e/Adapter/Scopes/GeneralTests.php
2 parents b078980 + cff2b6e commit 64b671e

26 files changed

Lines changed: 735 additions & 39 deletions

bin/cli.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require_once '/usr/src/code/vendor/autoload.php';
44

55
use Utopia\CLI\CLI;
6-
use Utopia\CLI\Console;
6+
use Utopia\Console;
77

88
ini_set('memory_limit', '-1');
99

bin/tasks/index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Utopia\Cache\Adapter\None as NoCache;
99
use Utopia\Cache\Cache;
1010
use Utopia\CLI\CLI;
11-
use Utopia\CLI\Console;
11+
use Utopia\Console;
1212
use Utopia\Database\Adapter\MariaDB;
1313
use Utopia\Database\Adapter\MySQL;
1414
use Utopia\Database\Adapter\Postgres;

bin/tasks/load.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use Swoole\Database\PDOPool;
77
use Utopia\Cache\Adapter\None as NoCache;
88
use Utopia\Cache\Cache;
9-
use Utopia\CLI\Console;
9+
use Utopia\Console;
1010
use Utopia\Database\Adapter\MariaDB;
1111
use Utopia\Database\Adapter\MySQL;
1212
use Utopia\Database\Adapter\Postgres;

bin/tasks/operators.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
use Utopia\Cache\Adapter\None as NoCache;
2020
use Utopia\Cache\Cache;
21-
use Utopia\CLI\Console;
21+
use Utopia\Console;
2222
use Utopia\Database\Adapter\MariaDB;
2323
use Utopia\Database\Adapter\MySQL;
2424
use Utopia\Database\Adapter\Postgres;

bin/tasks/query.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Utopia\Cache\Adapter\None as NoCache;
1010
use Utopia\Cache\Cache;
1111
use Utopia\CLI\CLI;
12-
use Utopia\CLI\Console;
12+
use Utopia\Console;
1313
use Utopia\Database\Adapter\MariaDB;
1414
use Utopia\Database\Adapter\MySQL;
1515
use Utopia\Database\Adapter\Postgres;

bin/tasks/relationships.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Swoole\Database\PDOPool;
1010
use Utopia\Cache\Adapter\None as NoCache;
1111
use Utopia\Cache\Cache;
12-
use Utopia\CLI\Console;
12+
use Utopia\Console;
1313
use Utopia\Database\Adapter\MariaDB;
1414
use Utopia\Database\Adapter\MySQL;
1515
use Utopia\Database\Adapter\Postgres;

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"ext-pdo": "*",
3939
"ext-mongodb": "*",
4040
"ext-mbstring": "*",
41-
"utopia-php/framework": "0.33.*",
41+
"utopia-php/validators": "0.2.*",
42+
"utopia-php/console": "0.1.*",
4243
"utopia-php/cache": "1.*",
4344
"utopia-php/pools": "1.*",
4445
"utopia-php/mongo": "1.*",
@@ -50,7 +51,7 @@
5051
"phpunit/phpunit": "^12.0",
5152
"brianium/paratest": "^7.7",
5253
"swoole/ide-helper": "5.1.3",
53-
"utopia-php/cli": "0.14.*",
54+
"utopia-php/cli": "0.22.*",
5455
"laravel/pint": "*",
5556
"phpstan/phpstan": "^2.0",
5657
"rregeer/phpunit-coverage-check": "0.3.*"

src/Database/Adapter.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ abstract class Adapter implements Feature\Attributes, Feature\Collections, Featu
3737

3838
protected bool $sharedTables = false;
3939

40-
protected ?int $tenant = null;
40+
protected int|string|null $tenant = null;
4141

4242
protected bool $tenantPerDocument = false;
4343

@@ -235,7 +235,7 @@ public function getSharedTables(): bool
235235
*
236236
* Set tenant to use if tables are shared
237237
*/
238-
public function setTenant(?int $tenant): bool
238+
public function setTenant(int|string|null $tenant): bool
239239
{
240240
$this->tenant = $tenant;
241241

@@ -247,7 +247,7 @@ public function setTenant(?int $tenant): bool
247247
*
248248
* Get tenant to use for shared tables
249249
*/
250-
public function getTenant(): ?int
250+
public function getTenant(): int|string|null
251251
{
252252
return $this->tenant;
253253
}
@@ -938,6 +938,19 @@ public function getSchemaAttributes(string $collection): array
938938
return [];
939939
}
940940

941+
/**
942+
* Get the physical schema indexes for a collection from the database engine.
943+
*
944+
* Returns physical index definitions from the database schema.
945+
*
946+
* @param string $collection The collection identifier.
947+
* @return array<Document>
948+
*/
949+
public function getSchemaIndexes(string $collection): array
950+
{
951+
return [];
952+
}
953+
941954
/**
942955
* Get the expected column type for a given attribute type.
943956
*

src/Database/Adapter/MariaDB.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,58 @@ protected function getSearchRelevanceRaw(Query $query, string $alias): ?array
18081808
];
18091809
}
18101810

1811+
public function getSupportForSchemaIndexes(): bool
1812+
{
1813+
return true;
1814+
}
1815+
1816+
public function getSchemaIndexes(string $collection): array
1817+
{
1818+
$schema = $this->getDatabase();
1819+
$collection = $this->getNamespace() . '_' . $this->filter($collection);
1820+
1821+
try {
1822+
$stmt = $this->getPDO()->prepare('
1823+
SELECT
1824+
INDEX_NAME as indexName,
1825+
COLUMN_NAME as columnName,
1826+
NON_UNIQUE as nonUnique,
1827+
SEQ_IN_INDEX as seqInIndex,
1828+
INDEX_TYPE as indexType,
1829+
SUB_PART as subPart
1830+
FROM INFORMATION_SCHEMA.STATISTICS
1831+
WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :table
1832+
ORDER BY INDEX_NAME, SEQ_IN_INDEX
1833+
');
1834+
$stmt->bindParam(':schema', $schema);
1835+
$stmt->bindParam(':table', $collection);
1836+
$stmt->execute();
1837+
$rows = $stmt->fetchAll();
1838+
$stmt->closeCursor();
1839+
1840+
$grouped = [];
1841+
foreach ($rows as $row) {
1842+
$name = $row['indexName'];
1843+
if (!isset($grouped[$name])) {
1844+
$grouped[$name] = [
1845+
'$id' => $name,
1846+
'indexName' => $name,
1847+
'indexType' => $row['indexType'],
1848+
'nonUnique' => (int)$row['nonUnique'],
1849+
'columns' => [],
1850+
'lengths' => [],
1851+
];
1852+
}
1853+
$grouped[$name]['columns'][] = $row['columnName'];
1854+
$grouped[$name]['lengths'][] = $row['subPart'] !== null ? (int)$row['subPart'] : null;
1855+
}
1856+
1857+
return \array_map(fn ($idx) => new Document($idx), \array_values($grouped));
1858+
} catch (PDOException $e) {
1859+
throw new DatabaseException('Failed to get schema indexes', $e->getCode(), $e);
1860+
}
1861+
}
1862+
18111863
protected function processException(PDOException $e): Exception
18121864
{
18131865
if ($e->getCode() === '22007' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 1366) {

src/Database/Adapter/Mongo.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,10 @@ public function createCollection(string $name, array $attributes = [], array $in
542542
{
543543
$id = $this->getNamespace().'_'.$this->filter($name);
544544

545-
// For metadata collections outside transactions, check if exists first
546-
if (! $this->inTransaction && $name === Database::METADATA && $this->exists($this->getNamespace(), $name)) {
545+
// In shared-tables mode or for metadata, the physical collection may
546+
// already exist for another tenant. Return early to avoid a
547+
// "Collection Exists" exception from the client.
548+
if (! $this->inTransaction && ($this->getSharedTables() || $name === Database::METADATA) && $this->exists($this->getNamespace(), $name)) {
547549
return true;
548550
}
549551

@@ -560,6 +562,16 @@ public function createCollection(string $name, array $attributes = [], array $in
560562
if ($e instanceof DuplicateException) {
561563
return true;
562564
}
565+
// Client throws code-0 "Collection Exists" when its pre-check
566+
// finds the collection. In shared-tables/metadata context this
567+
// is a no-op; otherwise re-throw as DuplicateException so
568+
// Database::createCollection() can run orphan reconciliation.
569+
if ($e->getCode() === 0 && stripos($e->getMessage(), 'Collection Exists') !== false) {
570+
if ($this->getSharedTables() || $name === Database::METADATA) {
571+
return true;
572+
}
573+
throw new DuplicateException('Collection already exists', $e->getCode(), $e);
574+
}
563575
throw $e;
564576
}
565577

0 commit comments

Comments
 (0)