diff --git a/src/Database/Database.php b/src/Database/Database.php index 32682716a..b2e16af45 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1790,16 +1790,19 @@ public function createCollection(string $id, array $attributes = [], array $inde } } - $created = false; - try { $this->adapter->createCollection($id, $attributes, $indexes); - $created = true; } catch (DuplicateException $e) { // Metadata check (above) already verified collection is absent // from metadata. A DuplicateException from the adapter means the // collection exists only in physical schema — an orphan from a prior - // partial failure. Skip creation and proceed to metadata creation. + // partial failure. Drop and recreate to ensure schema matches. + try { + $this->adapter->deleteCollection($id); + } catch (NotFoundException) { + // Already removed by a concurrent reconciler. + } + $this->adapter->createCollection($id, $attributes, $indexes); } if ($id === self::METADATA) { @@ -1809,12 +1812,10 @@ public function createCollection(string $id, array $attributes = [], array $inde try { $createdCollection = $this->silent(fn () => $this->createDocument(self::METADATA, $collection)); } catch (\Throwable $e) { - if ($created) { - try { - $this->cleanupCollection($id); - } catch (\Throwable $e) { - Console::error("Failed to rollback collection '{$id}': " . $e->getMessage()); - } + try { + $this->cleanupCollection($id); + } catch (\Throwable $e) { + Console::error("Failed to rollback collection '{$id}': " . $e->getMessage()); } throw new DatabaseException("Failed to create collection metadata for '{$id}': " . $e->getMessage(), previous: $e); } @@ -1856,7 +1857,7 @@ public function updateCollection(string $id, array $permissions, bool $documentS if ( $this->adapter->getSharedTables() - && $collection->getTenant() !== $this->adapter->getTenant() + && $collection->getTenant() != $this->adapter->getTenant() ) { throw new NotFoundException('Collection not found'); } @@ -1892,7 +1893,7 @@ public function getCollection(string $id): Document $id !== self::METADATA && $this->adapter->getSharedTables() && $collection->getTenant() !== null - && $collection->getTenant() !== $this->adapter->getTenant() + && $collection->getTenant() != $this->adapter->getTenant() ) { return new Document(); } @@ -1947,7 +1948,7 @@ public function getSizeOfCollection(string $collection): int throw new NotFoundException('Collection not found'); } - if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) { + if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) { throw new NotFoundException('Collection not found'); } @@ -1973,7 +1974,7 @@ public function getSizeOfCollectionOnDisk(string $collection): int throw new NotFoundException('Collection not found'); } - if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) { + if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) { throw new NotFoundException('Collection not found'); } @@ -2007,7 +2008,7 @@ public function deleteCollection(string $id): bool throw new NotFoundException('Collection not found'); } - if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) { + if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) { throw new NotFoundException('Collection not found'); } @@ -6054,11 +6055,15 @@ public function updateDocument(string $collection, string $id, Document $documen $document['$createdAt'] = ($createdAt === null || !$this->preserveDates) ? $old->getCreatedAt() : $createdAt; if ($this->adapter->getSharedTables()) { - $document['$tenant'] = $old->getTenant(); // Make sure user doesn't switch tenant + $tenant = $old->getTenant(); + $document['$tenant'] = $tenant; + $old->setAttribute('$tenant', $tenant); // Normalize for strict comparison } $document = new Document($document); - $relationships = \array_filter($collection->getAttribute('attributes', []), function ($attribute) { + $attributes = $collection->getAttribute('attributes', []); + + $relationships = \array_filter($attributes, function ($attribute) { return $attribute['type'] === Database::VAR_RELATIONSHIP; }); @@ -6159,7 +6164,6 @@ public function updateDocument(string $collection, string $id, Document $documen $oldValue = $old->getAttribute($key); - // If values are not equal we need to update document. if ($value !== $oldValue) { $shouldUpdate = true; break; @@ -7201,7 +7205,7 @@ public function upsertDocumentsWithIncrease( if ($document->getTenant() === null) { throw new DatabaseException('Missing tenant. Tenant must be set when tenant per document is enabled.'); } - if (!$old->isEmpty() && $old->getTenant() !== $document->getTenant()) { + if (!$old->isEmpty() && $old->getTenant() != $document->getTenant()) { throw new DatabaseException('Tenant cannot be changed.'); } } else { diff --git a/src/Database/Validator/Sequence.php b/src/Database/Validator/Sequence.php index d528cc4ea..7e3ebca27 100644 --- a/src/Database/Validator/Sequence.php +++ b/src/Database/Validator/Sequence.php @@ -41,16 +41,23 @@ public function isValid($value): bool return false; } - if (!\is_string($value)) { + if ($value === null) { + return true; + } + + if (!\is_string($value) && !\is_int($value)) { return false; } + if (!$this->primary) { + return true; + } + switch ($this->idAttributeType) { - case Database::VAR_UUID7: //UUID7 - 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; + case Database::VAR_UUID7: + 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; case Database::VAR_INTEGER: - $start = ($this->primary) ? 1 : 0; - $validator = new Range($start, Database::MAX_BIG_INT, Database::VAR_INTEGER); + $validator = new Range(1, Database::MAX_BIG_INT, Database::VAR_INTEGER); return $validator->isValid($value); default: diff --git a/tests/unit/Validator/StructureTest.php b/tests/unit/Validator/StructureTest.php index ffc2b62ee..f3b49864d 100644 --- a/tests/unit/Validator/StructureTest.php +++ b/tests/unit/Validator/StructureTest.php @@ -773,7 +773,7 @@ public function testId(): void 'id' => $sqlId, ]))); - $this->assertEquals(false, $validator->isValid(new Document([ + $this->assertEquals(true, $validator->isValid(new Document([ '$collection' => ID::custom('posts'), 'title' => 'My Title', 'description' => null,