2021-01-14 05:51:02 +13:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Appwrite\Migration;
|
|
|
|
|
2021-12-09 06:50:04 +13:00
|
|
|
use Appwrite\Database\Document as OldDocument;
|
|
|
|
use Appwrite\Database\Database as OldDatabase;
|
2021-01-25 21:26:52 +13:00
|
|
|
use PDO;
|
2021-12-09 06:50:04 +13:00
|
|
|
use Redis;
|
2021-01-25 21:26:52 +13:00
|
|
|
use Swoole\Runtime;
|
2021-01-15 01:05:49 +13:00
|
|
|
use Utopia\CLI\Console;
|
|
|
|
use Utopia\Exception;
|
2021-01-14 05:51:02 +13:00
|
|
|
|
|
|
|
abstract class Migration
|
|
|
|
{
|
2021-12-09 23:42:49 +13:00
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected array $options;
|
|
|
|
|
2021-01-19 03:43:55 +13:00
|
|
|
/**
|
|
|
|
* @var PDO
|
|
|
|
*/
|
2021-12-09 06:50:04 +13:00
|
|
|
protected PDO $db;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var Redis
|
|
|
|
*/
|
|
|
|
protected Redis $cache;
|
2021-01-15 01:05:49 +13:00
|
|
|
|
2021-01-19 03:43:55 +13:00
|
|
|
/**
|
|
|
|
* @var int
|
|
|
|
*/
|
2021-12-10 01:51:29 +13:00
|
|
|
protected int $limit = 500;
|
2021-12-09 06:50:04 +13:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var OldDocument
|
|
|
|
*/
|
|
|
|
protected OldDocument $project;
|
2021-01-15 03:09:48 +13:00
|
|
|
|
2021-01-19 03:43:55 +13:00
|
|
|
/**
|
2021-12-09 06:50:04 +13:00
|
|
|
* @var OldDatabase
|
2021-01-19 03:43:55 +13:00
|
|
|
*/
|
2021-12-09 06:50:04 +13:00
|
|
|
protected OldDatabase $oldProjectDB;
|
2021-01-19 03:43:55 +13:00
|
|
|
|
|
|
|
/**
|
2021-12-09 06:50:04 +13:00
|
|
|
* @var OldDatabase
|
2021-01-19 03:43:55 +13:00
|
|
|
*/
|
2021-12-09 06:50:04 +13:00
|
|
|
protected OldDatabase $oldConsoleDB;
|
2021-01-15 01:05:49 +13:00
|
|
|
|
2021-07-02 21:09:02 +12:00
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
public static array $versions = [
|
|
|
|
'0.6.0' => 'V05',
|
|
|
|
'0.7.0' => 'V06',
|
|
|
|
'0.8.0' => 'V07',
|
|
|
|
'0.9.0' => 'V08',
|
2021-07-13 04:21:12 +12:00
|
|
|
'0.9.1' => 'V08',
|
2021-07-22 21:02:07 +12:00
|
|
|
'0.9.2' => 'V08',
|
2021-07-28 00:43:08 +12:00
|
|
|
'0.9.3' => 'V08',
|
2021-08-10 20:30:39 +12:00
|
|
|
'0.9.4' => 'V08',
|
2021-08-31 00:25:23 +12:00
|
|
|
'0.10.0' => 'V09',
|
2021-09-03 23:57:49 +12:00
|
|
|
'0.10.1' => 'V09',
|
2021-09-07 01:45:43 +12:00
|
|
|
'0.10.2' => 'V09',
|
2021-09-09 23:21:29 +12:00
|
|
|
'0.10.3' => 'V09',
|
2021-09-16 02:06:49 +12:00
|
|
|
'0.10.4' => 'V09',
|
2021-10-16 05:56:35 +13:00
|
|
|
'0.11.0' => 'V10',
|
2021-12-09 06:50:04 +13:00
|
|
|
'0.12.0' => 'V11',
|
2022-01-06 04:40:51 +13:00
|
|
|
'0.12.1' => 'V11',
|
2021-07-02 21:09:02 +12:00
|
|
|
];
|
|
|
|
|
2021-01-15 01:05:49 +13:00
|
|
|
/**
|
|
|
|
* Migration constructor.
|
2021-10-06 20:53:33 +13:00
|
|
|
*
|
2021-12-13 23:59:13 +13:00
|
|
|
* @param PDO $db
|
|
|
|
* @param Redis|null $cache
|
|
|
|
* @param array $options
|
|
|
|
* @return void
|
2021-01-15 01:05:49 +13:00
|
|
|
*/
|
2021-12-09 23:42:49 +13:00
|
|
|
public function __construct(PDO $db, Redis $cache = null, array $options = [])
|
2021-01-15 01:05:49 +13:00
|
|
|
{
|
2021-12-09 23:42:49 +13:00
|
|
|
$this->options = $options;
|
2021-01-15 01:05:49 +13:00
|
|
|
$this->db = $db;
|
2021-12-13 23:59:13 +13:00
|
|
|
if (!is_null($cache)) {
|
2021-12-09 06:50:04 +13:00
|
|
|
$this->cache = $cache;
|
|
|
|
}
|
2021-01-15 01:05:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set project for migration.
|
2021-10-06 20:53:33 +13:00
|
|
|
*
|
2021-12-09 06:50:04 +13:00
|
|
|
* @param OldDocument $project
|
|
|
|
* @param OldDatabase $projectDB
|
|
|
|
* @param OldDatabase $oldConsoleDB
|
2021-10-06 20:53:33 +13:00
|
|
|
*
|
2021-12-09 06:50:04 +13:00
|
|
|
* @return self
|
2021-01-15 01:05:49 +13:00
|
|
|
*/
|
2021-12-09 06:50:04 +13:00
|
|
|
public function setProject(OldDocument $project, OldDatabase $projectDB, OldDatabase $oldConsoleDB): self
|
2021-01-15 01:05:49 +13:00
|
|
|
{
|
|
|
|
$this->project = $project;
|
2021-12-09 06:50:04 +13:00
|
|
|
|
|
|
|
$this->oldProjectDB = $projectDB;
|
|
|
|
$this->oldProjectDB->setNamespace('app_' . $project->getId());
|
|
|
|
|
|
|
|
$this->oldConsoleDB = $oldConsoleDB;
|
|
|
|
|
2021-01-15 01:05:49 +13:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Iterates through every document.
|
2021-10-06 20:53:33 +13:00
|
|
|
*
|
2021-01-19 03:43:55 +13:00
|
|
|
* @param callable $callback
|
2021-01-15 01:05:49 +13:00
|
|
|
*/
|
2021-01-21 22:57:15 +13:00
|
|
|
public function forEachDocument(callable $callback): void
|
2021-01-15 01:05:49 +13:00
|
|
|
{
|
2021-01-21 22:57:15 +13:00
|
|
|
$sum = $this->limit;
|
2021-01-15 03:09:48 +13:00
|
|
|
$offset = 0;
|
|
|
|
|
2021-01-21 22:57:15 +13:00
|
|
|
while ($sum >= $this->limit) {
|
2021-01-15 01:05:49 +13:00
|
|
|
$all = $this->projectDB->getCollection([
|
|
|
|
'limit' => $this->limit,
|
2021-01-15 03:09:48 +13:00
|
|
|
'offset' => $offset,
|
2021-01-15 01:05:49 +13:00
|
|
|
'orderType' => 'DESC',
|
|
|
|
]);
|
|
|
|
|
2021-01-15 03:09:48 +13:00
|
|
|
$sum = \count($all);
|
2021-04-15 19:56:45 +12:00
|
|
|
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
2021-01-15 01:05:49 +13:00
|
|
|
|
2021-01-15 03:09:48 +13:00
|
|
|
Console::log('Migrating: ' . $offset . ' / ' . $this->projectDB->getSum());
|
2021-01-25 21:26:52 +13:00
|
|
|
\Co\run(function () use ($all, $callback) {
|
|
|
|
foreach ($all as $document) {
|
|
|
|
go(function () use ($document, $callback) {
|
2021-09-03 20:36:58 +12:00
|
|
|
if (empty($document->getId()) || empty($document->getCollection())) {
|
2021-10-16 05:11:20 +13:00
|
|
|
if ($document->getCollection() !== 0) {
|
|
|
|
Console::warning('Skipped Document due to missing ID or Collection.');
|
|
|
|
}
|
2021-09-03 20:36:58 +12:00
|
|
|
return;
|
|
|
|
}
|
2021-01-25 21:26:52 +13:00
|
|
|
|
|
|
|
$old = $document->getArrayCopy();
|
|
|
|
$new = call_user_func($callback, $document);
|
|
|
|
|
2021-04-16 19:08:42 +12:00
|
|
|
if (!$this->check_diff_multi($new->getArrayCopy(), $old)) {
|
2021-01-25 21:26:52 +13:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2021-12-09 06:50:04 +13:00
|
|
|
$new = $this->projectDB->overwriteDocument($new->getArrayCopy());
|
2021-01-25 21:26:52 +13:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
Console::error('Failed to update document: ' . $th->getMessage());
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ($document && $new->getId() !== $document->getId()) {
|
|
|
|
throw new Exception('Duplication Error');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2021-01-15 01:05:49 +13:00
|
|
|
}
|
2021-01-25 21:26:52 +13:00
|
|
|
});
|
2021-01-15 01:05:49 +13:00
|
|
|
|
2021-01-15 03:09:48 +13:00
|
|
|
$offset += $this->limit;
|
2021-01-15 01:05:49 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-09 06:50:04 +13:00
|
|
|
/**
|
|
|
|
* Checks 2 arrays for differences.
|
|
|
|
*
|
|
|
|
* @param array $array1
|
|
|
|
* @param array $array2
|
|
|
|
* @return array
|
|
|
|
*/
|
2021-12-13 23:59:13 +13:00
|
|
|
public function check_diff_multi(array $array1, array $array2): array
|
2021-10-06 20:53:33 +13:00
|
|
|
{
|
2021-04-16 19:08:42 +12:00
|
|
|
$result = array();
|
2021-10-16 05:11:20 +13:00
|
|
|
|
2021-10-06 20:53:33 +13:00
|
|
|
foreach ($array1 as $key => $val) {
|
|
|
|
if (is_array($val) && isset($array2[$key])) {
|
2021-04-16 19:08:42 +12:00
|
|
|
$tmp = $this->check_diff_multi($val, $array2[$key]);
|
2021-10-06 20:53:33 +13:00
|
|
|
if ($tmp) {
|
2021-04-16 19:08:42 +12:00
|
|
|
$result[$key] = $tmp;
|
|
|
|
}
|
2021-10-06 20:53:33 +13:00
|
|
|
} elseif (!isset($array2[$key])) {
|
2021-04-16 19:08:42 +12:00
|
|
|
$result[$key] = null;
|
2021-10-06 20:53:33 +13:00
|
|
|
} elseif ($val !== $array2[$key]) {
|
2021-04-16 19:08:42 +12:00
|
|
|
$result[$key] = $array2[$key];
|
|
|
|
}
|
2021-10-16 05:11:20 +13:00
|
|
|
|
2021-10-06 20:53:33 +13:00
|
|
|
if (isset($array2[$key])) {
|
2021-04-16 19:08:42 +12:00
|
|
|
unset($array2[$key]);
|
|
|
|
}
|
|
|
|
}
|
2021-10-16 05:11:20 +13:00
|
|
|
|
2021-04-16 19:08:42 +12:00
|
|
|
$result = array_merge($result, $array2);
|
2021-10-16 05:11:20 +13:00
|
|
|
|
2021-04-16 19:08:42 +12:00
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2021-01-15 01:05:49 +13:00
|
|
|
/**
|
|
|
|
* Executes migration for set project.
|
|
|
|
*/
|
|
|
|
abstract public function execute(): void;
|
2021-01-14 05:51:02 +13:00
|
|
|
}
|