Skip to content

Commit 3a753ae

Browse files
authored
Merge pull request #839 from utopia-php/fix-collection-recreate
2 parents f84590d + a67be9c commit 3a753ae

File tree

3 files changed

+36
-25
lines changed

3 files changed

+36
-25
lines changed

src/Database/Database.php

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,16 +1790,19 @@ public function createCollection(string $id, array $attributes = [], array $inde
17901790
}
17911791
}
17921792

1793-
$created = false;
1794-
17951793
try {
17961794
$this->adapter->createCollection($id, $attributes, $indexes);
1797-
$created = true;
17981795
} catch (DuplicateException $e) {
17991796
// Metadata check (above) already verified collection is absent
18001797
// from metadata. A DuplicateException from the adapter means the
18011798
// collection exists only in physical schema — an orphan from a prior
1802-
// partial failure. Skip creation and proceed to metadata creation.
1799+
// partial failure. Drop and recreate to ensure schema matches.
1800+
try {
1801+
$this->adapter->deleteCollection($id);
1802+
} catch (NotFoundException) {
1803+
// Already removed by a concurrent reconciler.
1804+
}
1805+
$this->adapter->createCollection($id, $attributes, $indexes);
18031806
}
18041807

18051808
if ($id === self::METADATA) {
@@ -1809,12 +1812,10 @@ public function createCollection(string $id, array $attributes = [], array $inde
18091812
try {
18101813
$createdCollection = $this->silent(fn () => $this->createDocument(self::METADATA, $collection));
18111814
} catch (\Throwable $e) {
1812-
if ($created) {
1813-
try {
1814-
$this->cleanupCollection($id);
1815-
} catch (\Throwable $e) {
1816-
Console::error("Failed to rollback collection '{$id}': " . $e->getMessage());
1817-
}
1815+
try {
1816+
$this->cleanupCollection($id);
1817+
} catch (\Throwable $e) {
1818+
Console::error("Failed to rollback collection '{$id}': " . $e->getMessage());
18181819
}
18191820
throw new DatabaseException("Failed to create collection metadata for '{$id}': " . $e->getMessage(), previous: $e);
18201821
}
@@ -1856,7 +1857,7 @@ public function updateCollection(string $id, array $permissions, bool $documentS
18561857

18571858
if (
18581859
$this->adapter->getSharedTables()
1859-
&& $collection->getTenant() !== $this->adapter->getTenant()
1860+
&& $collection->getTenant() != $this->adapter->getTenant()
18601861
) {
18611862
throw new NotFoundException('Collection not found');
18621863
}
@@ -1892,7 +1893,7 @@ public function getCollection(string $id): Document
18921893
$id !== self::METADATA
18931894
&& $this->adapter->getSharedTables()
18941895
&& $collection->getTenant() !== null
1895-
&& $collection->getTenant() !== $this->adapter->getTenant()
1896+
&& $collection->getTenant() != $this->adapter->getTenant()
18961897
) {
18971898
return new Document();
18981899
}
@@ -1947,7 +1948,7 @@ public function getSizeOfCollection(string $collection): int
19471948
throw new NotFoundException('Collection not found');
19481949
}
19491950

1950-
if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) {
1951+
if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) {
19511952
throw new NotFoundException('Collection not found');
19521953
}
19531954

@@ -1973,7 +1974,7 @@ public function getSizeOfCollectionOnDisk(string $collection): int
19731974
throw new NotFoundException('Collection not found');
19741975
}
19751976

1976-
if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) {
1977+
if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) {
19771978
throw new NotFoundException('Collection not found');
19781979
}
19791980

@@ -2007,7 +2008,7 @@ public function deleteCollection(string $id): bool
20072008
throw new NotFoundException('Collection not found');
20082009
}
20092010

2010-
if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) {
2011+
if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) {
20112012
throw new NotFoundException('Collection not found');
20122013
}
20132014

@@ -6054,11 +6055,15 @@ public function updateDocument(string $collection, string $id, Document $documen
60546055
$document['$createdAt'] = ($createdAt === null || !$this->preserveDates) ? $old->getCreatedAt() : $createdAt;
60556056

60566057
if ($this->adapter->getSharedTables()) {
6057-
$document['$tenant'] = $old->getTenant(); // Make sure user doesn't switch tenant
6058+
$tenant = $old->getTenant();
6059+
$document['$tenant'] = $tenant;
6060+
$old->setAttribute('$tenant', $tenant); // Normalize for strict comparison
60586061
}
60596062
$document = new Document($document);
60606063

6061-
$relationships = \array_filter($collection->getAttribute('attributes', []), function ($attribute) {
6064+
$attributes = $collection->getAttribute('attributes', []);
6065+
6066+
$relationships = \array_filter($attributes, function ($attribute) {
60626067
return $attribute['type'] === Database::VAR_RELATIONSHIP;
60636068
});
60646069

@@ -6159,7 +6164,6 @@ public function updateDocument(string $collection, string $id, Document $documen
61596164

61606165
$oldValue = $old->getAttribute($key);
61616166

6162-
// If values are not equal we need to update document.
61636167
if ($value !== $oldValue) {
61646168
$shouldUpdate = true;
61656169
break;
@@ -7201,7 +7205,7 @@ public function upsertDocumentsWithIncrease(
72017205
if ($document->getTenant() === null) {
72027206
throw new DatabaseException('Missing tenant. Tenant must be set when tenant per document is enabled.');
72037207
}
7204-
if (!$old->isEmpty() && $old->getTenant() !== $document->getTenant()) {
7208+
if (!$old->isEmpty() && $old->getTenant() != $document->getTenant()) {
72057209
throw new DatabaseException('Tenant cannot be changed.');
72067210
}
72077211
} else {

src/Database/Validator/Sequence.php

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,23 @@ public function isValid($value): bool
4141
return false;
4242
}
4343

44-
if (!\is_string($value)) {
44+
if ($value === null) {
45+
return true;
46+
}
47+
48+
if (!\is_string($value) && !\is_int($value)) {
4549
return false;
4650
}
4751

52+
if (!$this->primary) {
53+
return true;
54+
}
55+
4856
switch ($this->idAttributeType) {
49-
case Database::VAR_UUID7: //UUID7
50-
return preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-7[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i', $value) === 1;
57+
case Database::VAR_UUID7:
58+
return \is_string($value) && preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-7[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i', $value) === 1;
5159
case Database::VAR_INTEGER:
52-
$start = ($this->primary) ? 1 : 0;
53-
$validator = new Range($start, Database::MAX_BIG_INT, Database::VAR_INTEGER);
60+
$validator = new Range(1, Database::MAX_BIG_INT, Database::VAR_INTEGER);
5461
return $validator->isValid($value);
5562

5663
default:

tests/unit/Validator/StructureTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ public function testId(): void
773773
'id' => $sqlId,
774774
])));
775775

776-
$this->assertEquals(false, $validator->isValid(new Document([
776+
$this->assertEquals(true, $validator->isValid(new Document([
777777
'$collection' => ID::custom('posts'),
778778
'title' => 'My Title',
779779
'description' => null,

0 commit comments

Comments
 (0)