Skip to content

Commit 6cdbe98

Browse files
committed
Fix upsert + test
1 parent 1ada153 commit 6cdbe98

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

src/Database/Database.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8202,8 +8202,9 @@ public function encode(Document $collection, Document $document, bool $applyDefa
82028202
if (is_null($value) && is_null($default)) {
82038203
// Non-required array columns are NOT NULL with DEFAULT '[]', so coerce null to empty array.
82048204
// Required arrays must remain null so the Structure validator catches the missing value.
8205+
// Only coerce when applying defaults (inserts) to avoid clearing existing values during partial updates.
82058206
$required = $attribute['required'] ?? false;
8206-
if ($array && !$required) {
8207+
if ($applyDefaults && $array && !$required) {
82078208
$document->setAttribute($key, []);
82088209
}
82098210
continue;

tests/e2e/Adapter/Scopes/DocumentTests.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4403,6 +4403,63 @@ public function testEncodeDecode(): void
44034403
new Document(['$id' => '3', 'label' => 'z']),
44044404
], $result->getAttribute('tags'));
44054405
}
4406+
4407+
/**
4408+
* Regression: encode() with applyDefaults:false must not coerce
4409+
* unspecified optional array attributes to [], which would clear
4410+
* their stored values during partial updates.
4411+
*/
4412+
public function testEncodePartialUpdatePreservesArrayAttributes(): void
4413+
{
4414+
$collection = new Document([
4415+
'$collection' => ID::custom(Database::METADATA),
4416+
'$id' => ID::custom('items'),
4417+
'name' => 'Items',
4418+
'attributes' => [
4419+
[
4420+
'$id' => ID::custom('title'),
4421+
'type' => Database::VAR_STRING,
4422+
'format' => '',
4423+
'size' => 256,
4424+
'signed' => true,
4425+
'required' => false,
4426+
'default' => null,
4427+
'array' => false,
4428+
'filters' => [],
4429+
],
4430+
[
4431+
'$id' => ID::custom('tags'),
4432+
'type' => Database::VAR_STRING,
4433+
'format' => '',
4434+
'size' => 255,
4435+
'signed' => true,
4436+
'required' => false,
4437+
'default' => null,
4438+
'array' => true,
4439+
'filters' => [],
4440+
],
4441+
],
4442+
'indexes' => [],
4443+
]);
4444+
4445+
// Partial update: only 'title' is provided, 'tags' is absent
4446+
$partialUpdate = new Document([
4447+
'$id' => ID::custom('doc1'),
4448+
'title' => 'Updated Title',
4449+
]);
4450+
4451+
/** @var Database $database */
4452+
$database = $this->getDatabase();
4453+
4454+
$result = $database->encode($collection, $partialUpdate, applyDefaults: false);
4455+
4456+
$this->assertEquals('Updated Title', $result->getAttribute('title'));
4457+
$this->assertNull(
4458+
$result->getAttribute('tags'),
4459+
'Unspecified optional array attribute must remain null during partial update, not be coerced to []'
4460+
);
4461+
}
4462+
44064463
/**
44074464
* @depends testGetDocument
44084465
*/

0 commit comments

Comments
 (0)