2024-07-17 05:52:17 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Appwrite\Migration\Version;
|
|
|
|
|
|
|
|
|
|
use Appwrite\Migration\Migration;
|
|
|
|
|
use Exception;
|
|
|
|
|
use Throwable;
|
|
|
|
|
use Utopia\CLI\Console;
|
|
|
|
|
use Utopia\Database\Database;
|
2024-07-17 06:20:34 +00:00
|
|
|
use Utopia\Database\DateTime;
|
2024-07-17 05:52:17 +00:00
|
|
|
use Utopia\Database\Document;
|
|
|
|
|
|
2024-07-17 05:54:37 +00:00
|
|
|
class V21 extends Migration
|
2024-07-17 05:52:17 +00:00
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* @throws Throwable
|
|
|
|
|
*/
|
|
|
|
|
public function execute(): void
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Disable SubQueries for Performance.
|
|
|
|
|
*/
|
|
|
|
|
foreach (['subQueryIndexes', 'subQueryPlatforms', 'subQueryDomains', 'subQueryKeys', 'subQueryWebhooks', 'subQuerySessions', 'subQueryTokens', 'subQueryMemberships', 'subQueryVariables', 'subQueryChallenges', 'subQueryProjectVariables', 'subQueryTargets', 'subQueryTopicTargets'] as $name) {
|
|
|
|
|
Database::addFilter(
|
|
|
|
|
$name,
|
|
|
|
|
fn () => null,
|
|
|
|
|
fn () => []
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')');
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->dbForProject->setNamespace("_{$this->project->getInternalId()}");
|
2024-07-17 05:52:17 +00:00
|
|
|
|
|
|
|
|
Console::info('Migrating Collections');
|
|
|
|
|
$this->migrateCollections();
|
|
|
|
|
|
2024-07-30 20:53:18 +00:00
|
|
|
if ($this->project->getInternalId() !== 'console') {
|
|
|
|
|
Console::info('Migrating Buckets');
|
|
|
|
|
$this->migrateBuckets();
|
|
|
|
|
}
|
2024-07-30 21:39:32 +00:00
|
|
|
|
|
|
|
|
Console::info('Migrating Documents');
|
|
|
|
|
$this->forEachDocument([$this, 'fixDocument']);
|
2024-07-17 05:52:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Migrate Collections.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
* @throws Exception|Throwable
|
|
|
|
|
*/
|
|
|
|
|
private function migrateCollections(): void
|
|
|
|
|
{
|
|
|
|
|
$internalProjectId = $this->project->getInternalId();
|
|
|
|
|
$collectionType = match ($internalProjectId) {
|
|
|
|
|
'console' => 'console',
|
|
|
|
|
default => 'projects',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$collections = $this->collections[$collectionType];
|
|
|
|
|
foreach ($collections as $collection) {
|
|
|
|
|
$id = $collection['$id'];
|
|
|
|
|
|
|
|
|
|
Console::log("Migrating Collection \"{$id}\"");
|
|
|
|
|
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->dbForProject->setNamespace("_$internalProjectId");
|
2024-07-17 05:52:17 +00:00
|
|
|
|
|
|
|
|
switch ($id) {
|
|
|
|
|
case 'projects':
|
|
|
|
|
// Create accessedAt attribute
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'accessedAt');
|
2024-07-17 05:52:17 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'accessedAt' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
2024-07-24 07:00:20 +00:00
|
|
|
break;
|
2025-04-25 23:06:35 +00:00
|
|
|
case 'rules':
|
|
|
|
|
$attributesToCreate = ['owner', 'region'];
|
|
|
|
|
foreach ($attributesToCreate as $attribute) {
|
|
|
|
|
// Create attribute
|
|
|
|
|
try {
|
2025-05-17 21:01:39 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, $attribute);
|
2025-04-25 23:06:35 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'$attribute' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$indexesToCreate = ['_key_owner', '_key_region'];
|
|
|
|
|
foreach ($indexesToCreate as $index) {
|
|
|
|
|
// Create index
|
|
|
|
|
try {
|
2025-05-17 21:01:39 +00:00
|
|
|
$this->createIndexFromCollection($this->dbForProject, $id, $index);
|
2025-04-25 23:06:35 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'$index' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2024-08-21 11:22:24 +00:00
|
|
|
case 'platforms':
|
|
|
|
|
// Increase 'type' length to 255
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->dbForProject->updateAttribute($id, 'type', size: 255);
|
2024-08-21 11:22:24 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'type' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
break;
|
2025-04-25 23:06:35 +00:00
|
|
|
case 'installations':
|
|
|
|
|
$attributesToCreate = ['personalAccessToken', 'personalAccessTokenExpiry', 'personalRefreshToken'];
|
|
|
|
|
foreach ($attributesToCreate as $attribute) {
|
|
|
|
|
// Create attribute
|
|
|
|
|
try {
|
2025-05-17 21:01:39 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, $attribute);
|
2025-04-25 23:06:35 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'$attribute' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2025-04-10 22:43:13 +00:00
|
|
|
case 'migrations':
|
|
|
|
|
// Create destination attribute
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'destination');
|
2025-04-10 22:43:13 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'destination' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
break;
|
2024-07-17 05:52:17 +00:00
|
|
|
case 'schedules':
|
|
|
|
|
// Create data attribute
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'data');
|
2024-07-17 05:52:17 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'data' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2025-04-10 22:43:13 +00:00
|
|
|
case 'databases':
|
|
|
|
|
// Create originalId attribute
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'originalId');
|
2025-04-10 22:43:13 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'originalId' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
break;
|
2024-07-17 05:52:17 +00:00
|
|
|
case 'functions':
|
|
|
|
|
// Create scopes attribute
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'scopes');
|
2024-07-17 05:52:17 +00:00
|
|
|
} catch (Throwable $th) {
|
|
|
|
|
Console::warning("'scopes' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-14 02:48:40 +00:00
|
|
|
// Create specification attribute
|
2024-07-22 10:40:05 +00:00
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'specification');
|
2024-07-22 10:40:05 +00:00
|
|
|
} catch (Throwable $th) {
|
2024-08-14 02:48:40 +00:00
|
|
|
Console::warning("'specification' from {$id}: {$th->getMessage()}");
|
2024-07-22 10:40:05 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-17 05:52:17 +00:00
|
|
|
break;
|
|
|
|
|
case 'executions':
|
|
|
|
|
// Create requestMethod index
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createIndexFromCollection($this->dbForProject, $id, '_key_requestMethod');
|
2024-07-17 05:52:17 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'_key_requestMethod' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create requestPath index
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createIndexFromCollection($this->dbForProject, $id, '_key_requestPath');
|
2024-07-17 05:52:17 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'_key_requestPath' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create deployment index
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createIndexFromCollection($this->dbForProject, $id, '_key_deployment');
|
2024-07-17 05:52:17 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'_key_deployment' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
2024-07-24 07:11:48 +00:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
/**
|
|
|
|
|
* Create 'scheduledAt' attribute
|
|
|
|
|
*/
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'scheduledAt');
|
2024-07-24 07:11:48 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'scheduledAt' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
/**
|
|
|
|
|
* Create 'scheduleInternalId' attribute
|
|
|
|
|
*/
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'scheduleInternalId');
|
2024-07-24 07:11:48 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'scheduleInternalId' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
/**
|
|
|
|
|
* Create 'scheduleId' attribute
|
|
|
|
|
*/
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $id, 'scheduleId');
|
2024-07-24 07:11:48 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'scheduleId' from {$id}: {$th->getMessage()}");
|
|
|
|
|
}
|
2024-08-19 05:52:07 +00:00
|
|
|
break;
|
2024-07-17 05:52:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usleep(50000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fix run on each document
|
|
|
|
|
*
|
|
|
|
|
* @param Document $document
|
|
|
|
|
* @return Document
|
|
|
|
|
*/
|
|
|
|
|
protected function fixDocument(Document $document): Document
|
|
|
|
|
{
|
|
|
|
|
switch ($document->getCollection()) {
|
|
|
|
|
case 'projects':
|
|
|
|
|
/**
|
|
|
|
|
* Bump version number.
|
|
|
|
|
*/
|
|
|
|
|
$document->setAttribute('version', '1.6.0');
|
2024-07-22 02:38:17 +00:00
|
|
|
|
|
|
|
|
// Add accessedAt attribute
|
2024-07-17 06:20:42 +00:00
|
|
|
$document->setAttribute('accessedAt', DateTime::now());
|
2024-07-17 05:52:17 +00:00
|
|
|
break;
|
2024-07-22 10:40:05 +00:00
|
|
|
case 'functions':
|
2025-04-25 23:07:59 +00:00
|
|
|
// Set scopes attribute
|
|
|
|
|
if (empty($document->getAttribute('scopes', []))) {
|
|
|
|
|
$document->setAttribute('scopes', []);
|
|
|
|
|
}
|
2024-07-22 10:40:05 +00:00
|
|
|
|
2025-04-25 23:07:59 +00:00
|
|
|
// Set specification attribute
|
|
|
|
|
if (empty($document->getAttribute('specification'))) {
|
2025-05-17 21:01:39 +00:00
|
|
|
$document->setAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT);
|
2025-04-25 23:07:59 +00:00
|
|
|
}
|
2024-07-17 05:52:17 +00:00
|
|
|
}
|
2024-07-22 10:40:05 +00:00
|
|
|
|
2024-07-17 05:52:17 +00:00
|
|
|
return $document;
|
|
|
|
|
}
|
2024-07-30 20:53:18 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Migrating Buckets.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2024-08-21 11:22:24 +00:00
|
|
|
private function migrateBuckets(): void
|
2024-07-30 20:53:18 +00:00
|
|
|
{
|
2025-05-17 21:01:39 +00:00
|
|
|
$this->dbForProject->forEach('buckets', function (Document $bucket) {
|
2024-07-30 20:53:18 +00:00
|
|
|
$bucketId = 'bucket_' . $bucket['$internalId'];
|
|
|
|
|
|
2025-04-25 23:06:35 +00:00
|
|
|
Console::log("Migrating Bucket {$bucketId} {$bucket->getId()} ({$bucket->getAttribute('name')})");
|
|
|
|
|
|
2024-07-30 21:39:32 +00:00
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->dbForProject->updateAttribute($bucketId, 'metadata', size: 65534);
|
2025-04-25 23:06:35 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'metadata' from {$bucketId}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2025-05-17 21:01:39 +00:00
|
|
|
$this->createAttributeFromCollection($this->dbForProject, $bucketId, 'transformedAt', 'files');
|
2025-04-25 23:06:35 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'transformedAt' from {$bucketId}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2025-05-17 21:01:39 +00:00
|
|
|
$this->createIndexFromCollection($this->dbForProject, $bucketId, '_key_transformedAt', 'files');
|
2025-04-25 23:06:35 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::warning("'_key_transformedAt' from {$bucketId}: {$th->getMessage()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2025-05-16 05:24:11 +00:00
|
|
|
$this->dbForProject->purgeCachedCollection($bucketId);
|
2024-07-30 21:39:32 +00:00
|
|
|
} catch (\Throwable $th) {
|
2025-04-25 23:06:35 +00:00
|
|
|
Console::warning("purging {$bucketId}: {$th->getMessage()}");
|
2024-07-30 21:39:32 +00:00
|
|
|
}
|
2025-05-17 21:01:39 +00:00
|
|
|
});
|
2024-07-30 20:53:18 +00:00
|
|
|
}
|
2024-07-17 05:52:17 +00:00
|
|
|
}
|