diff --git a/src/Database/Validator/Structure.php b/src/Database/Validator/Structure.php index 4e3f66ec4..22f31a57f 100644 --- a/src/Database/Validator/Structure.php +++ b/src/Database/Validator/Structure.php @@ -267,6 +267,11 @@ protected function checkForAllRequiredValues(array $structure, array $attributes $keys[$name] = $attribute; // List of allowed attributes to help find unknown ones if ($required && !isset($structure[$name])) { + // Documents stored before the attribute became required hold null, and may keep it + if ($this->currentDocument !== null && $this->currentDocument->getAttribute($name) === null) { + continue; + } + $this->message = 'Missing required attribute "'.$name.'"'; return false; } @@ -333,6 +338,10 @@ protected function checkForInvalidAttributeValues(Document $document, array $str continue; } + if (is_null($value) && $this->currentDocument !== null && $this->currentDocument->getAttribute($key) === null) { + continue; + } + if ($type === Database::VAR_RELATIONSHIP) { continue; } diff --git a/tests/unit/Validator/StructureTest.php b/tests/unit/Validator/StructureTest.php index 71c90577c..e82a1cae5 100644 --- a/tests/unit/Validator/StructureTest.php +++ b/tests/unit/Validator/StructureTest.php @@ -242,6 +242,38 @@ public function testRequiredKeys(): void $this->assertEquals('Invalid document structure: Missing required attribute "title"', $validator->getDescription()); } + public function testRequiredKeyStoredAsNull(): void + { + $document = [ + '$collection' => ID::custom('posts'), + 'description' => 'Demo description', + 'rating' => 5, + 'price' => 1.99, + 'published' => true, + 'feedback' => 'team@appwrite.io', + '$createdAt' => '2000-04-01T12:00:00.000+00:00', + '$updatedAt' => '2000-04-01T12:00:00.000+00:00' + ]; + + $validator = new Structure( + new Document($this->collection), + Database::VAR_INTEGER, + currentDocument: new Document(['title' => null]) + ); + + $this->assertTrue($validator->isValid(new Document($document)), $validator->getDescription()); + $this->assertTrue($validator->isValid(new Document([...$document, 'title' => null])), $validator->getDescription()); + + $validator = new Structure( + new Document($this->collection), + Database::VAR_INTEGER, + currentDocument: new Document(['title' => 'My Title']) + ); + + $this->assertFalse($validator->isValid(new Document([...$document, 'title' => null]))); + $this->assertEquals('Invalid document structure: Missing required attribute "title"', $validator->getDescription()); + } + public function testNullValues(): void { $validator = new Structure(