Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Database/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,32 @@ public function clearTimeout(string $event): void
$this->before($event, 'timeout');
}

/**
* Bulk update attributes for many documents by their IDs.
*
* Default implementation performs per-ID updates using updateDocument with
* permissions update skipped. Adapters can override for optimized paths.
*
* @param Document $collection
* @param array<string> $ids
* @param array<string,mixed> $attributes Encoded attribute keys expected by adapter
* @return int Number of documents processed
*/
public function updateManyByIds(Document $collection, array $ids, array $attributes): int
{
if (empty($ids) || empty($attributes)) {
return 0;
}

$count = 0;
foreach ($ids as $id) {
$this->updateDocument($collection, $id, new Document($attributes), true);
$count++;
}

return $count;
}

/**
* Start a new transaction.
*
Expand Down
5 changes: 5 additions & 0 deletions src/Database/Adapter/Pool.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,11 @@ public function updateDocuments(Document $collection, Document $updates, array $
return $this->delegate(__FUNCTION__, \func_get_args());
}

public function updateManyByIds(Document $collection, array $ids, array $attributes): int
{
return $this->delegate(__FUNCTION__, \func_get_args());
}

public function upsertDocuments(Document $collection, string $attribute, array $changes): array
{
return $this->delegate(__FUNCTION__, \func_get_args());
Expand Down
72 changes: 72 additions & 0 deletions src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -2100,6 +2100,78 @@ public function createDocuments(Document $collection, array $documents): array
return $documents;
}

/**
* Bulk update attributes for many documents by their IDs
*
* @param Document $collection
* @param array<string> $ids
* @param array<string,mixed> $attributes Public attribute keys (e.g. "$updatedAt", "author")
* @return int Number of rows updated
* @throws \Exception
*/
public function updateManyByIds(Document $collection, array $ids, array $attributes): int
{
if (empty($ids) || empty($attributes)) {
return 0;
}

$collectionId = $this->filter($collection->getId());

// Map attribute keys to internal column names and build bindings
$binds = [];
$setParts = [];
$bindIndex = 0;

foreach ($attributes as $key => $value) {
$internal = $this->filter($this->getInternalKeyForAttribute($key));

// JSON encode arrays/objects; cast bools to int
if (\is_array($value)) {
$value = \json_encode($value);
} elseif (\is_bool($value)) {
$value = (int) $value;
}

$bindKey = ":val_{$bindIndex}";
$setParts[] = "{$this->quote($internal)} = {$bindKey}";
$binds[$bindKey] = $value;
$bindIndex++;
}

// Build IN list for IDs
$idPlaceholders = [];
foreach ($ids as $i => $id) {
$ph = ":id_{$i}";
$idPlaceholders[] = $ph;
$binds[$ph] = $id;
}

$tenantClause = '';
if ($this->sharedTables) {
$tenantClause = " AND {$this->quote('_tenant')} = :_tenant";
$binds[':_tenant'] = $this->getTenant();
}

$setSQL = \implode(', ', $setParts);
$inSQL = \implode(', ', $idPlaceholders);

$sql = "
UPDATE {$this->getSQLTable($collectionId)}
SET {$setSQL}
WHERE {$this->quote('_uid')} IN ({$inSQL}){$tenantClause}
";
Comment on lines +2158 to +2162
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the scenario where we want to set the same values on many documents but not use updateDocuments?


$stmt = $this->getPDO()->prepare($sql);

foreach ($binds as $key => $val) {
$stmt->bindValue($key, $val, $this->getPDOType($val));
}

$this->execute($stmt);

return $stmt->rowCount();
}

/**
* @param Document $collection
* @param string $attribute
Expand Down
Loading