Merge pull request #46476 from nextcloud/enh/noid/migration-attributes
Migration Attributespull/46885/head
commit
18c0bcb2da
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Testing\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCP\Migration\Attributes\AddColumn;
|
||||
use OCP\Migration\Attributes\AddIndex;
|
||||
use OCP\Migration\Attributes\ColumnType;
|
||||
use OCP\Migration\Attributes\CreateTable;
|
||||
use OCP\Migration\Attributes\DropColumn;
|
||||
use OCP\Migration\Attributes\DropIndex;
|
||||
use OCP\Migration\Attributes\DropTable;
|
||||
use OCP\Migration\Attributes\IndexType;
|
||||
use OCP\Migration\Attributes\ModifyColumn;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
|
||||
#[DropTable(table: 'old_table')]
|
||||
#[CreateTable(table: 'new_table', description: 'Table is used to store things, but also to get more things', notes: ['this is a notice', 'and another one, if really needed'])]
|
||||
#[AddColumn(table: 'my_table')]
|
||||
#[AddColumn(table: 'my_table', name: 'another_field')]
|
||||
#[AddColumn(table: 'other_table', name: 'last_one', type: ColumnType::DATE)]
|
||||
#[AddIndex(table: 'my_table')]
|
||||
#[AddIndex(table: 'my_table', type: IndexType::PRIMARY)]
|
||||
#[DropColumn(table: 'other_table')]
|
||||
#[DropColumn(table: 'other_table', name: 'old_column', description: 'field is not used anymore and replaced by \'last_one\'')]
|
||||
#[DropIndex(table: 'other_table')]
|
||||
#[ModifyColumn(table: 'other_table')]
|
||||
#[ModifyColumn(table: 'other_table', name: 'this_field')]
|
||||
#[ModifyColumn(table: 'other_table', name: 'this_field', type: ColumnType::BIGINT)]
|
||||
class Version30000Date20240102030405 extends SimpleMigrationStep {
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OC\Core\Command\Db\Migrations;
|
||||
|
||||
use OC\Migration\MetadataManager;
|
||||
use OCP\App\IAppManager;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class GenerateMetadataCommand extends Command {
|
||||
public function __construct(
|
||||
private readonly MetadataManager $metadataManager,
|
||||
private readonly IAppManager $appManager,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
$this->setName('migrations:generate-metadata')
|
||||
->setHidden(true)
|
||||
->setDescription('Generate metadata from DB migrations - internal and should not be used');
|
||||
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$output->writeln(
|
||||
json_encode(
|
||||
[
|
||||
'migrations' => $this->extractMigrationMetadata()
|
||||
],
|
||||
JSON_PRETTY_PRINT
|
||||
)
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function extractMigrationMetadata(): array {
|
||||
return [
|
||||
'core' => $this->extractMigrationMetadataFromCore(),
|
||||
'apps' => $this->extractMigrationMetadataFromApps()
|
||||
];
|
||||
}
|
||||
|
||||
private function extractMigrationMetadataFromCore(): array {
|
||||
return $this->metadataManager->extractMigrationAttributes('core');
|
||||
}
|
||||
|
||||
/**
|
||||
* get all apps and extract attributes
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function extractMigrationMetadataFromApps(): array {
|
||||
$allApps = \OC_App::getAllApps();
|
||||
$metadata = [];
|
||||
foreach ($allApps as $appId) {
|
||||
// We need to load app before being able to extract Migrations
|
||||
// If app was not enabled before, we will disable it afterward.
|
||||
$alreadyLoaded = $this->appManager->isInstalled($appId);
|
||||
if (!$alreadyLoaded) {
|
||||
$this->appManager->loadApp($appId);
|
||||
}
|
||||
$metadata[$appId] = $this->metadataManager->extractMigrationAttributes($appId);
|
||||
if (!$alreadyLoaded) {
|
||||
$this->appManager->disableApp($appId);
|
||||
}
|
||||
}
|
||||
return $metadata;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OC\Core\Command\Db\Migrations;
|
||||
|
||||
use OC\Migration\MetadataManager;
|
||||
use OC\Updater\ReleaseMetadata;
|
||||
use OCP\Migration\Attributes\MigrationAttribute;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableCell;
|
||||
use Symfony\Component\Console\Helper\TableCellStyle;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class PreviewCommand extends Command {
|
||||
private bool $initiated = false;
|
||||
public function __construct(
|
||||
private readonly MetadataManager $metadataManager,
|
||||
private readonly ReleaseMetadata $releaseMetadata,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void {
|
||||
$this
|
||||
->setName('migrations:preview')
|
||||
->setDescription('Get preview of available DB migrations in case of initiating an upgrade')
|
||||
->addArgument('version', InputArgument::REQUIRED, 'The destination version number');
|
||||
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$version = $input->getArgument('version');
|
||||
if (filter_var($version, FILTER_VALIDATE_URL)) {
|
||||
$metadata = $this->releaseMetadata->downloadMetadata($version);
|
||||
} elseif (str_starts_with($version, '/')) {
|
||||
$metadata = json_decode(file_get_contents($version), true, flags: JSON_THROW_ON_ERROR);
|
||||
} else {
|
||||
$metadata = $this->releaseMetadata->getMetadata($version);
|
||||
}
|
||||
|
||||
$parsed = $this->metadataManager->getMigrationsAttributesFromReleaseMetadata($metadata['migrations'] ?? [], true);
|
||||
|
||||
$table = new Table($output);
|
||||
$this->displayMigrations($table, 'core', $parsed['core'] ?? []);
|
||||
foreach ($parsed['apps'] as $appId => $migrations) {
|
||||
if (!empty($migrations)) {
|
||||
$this->displayMigrations($table, $appId, $migrations);
|
||||
}
|
||||
}
|
||||
$table->render();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function displayMigrations(Table $table, string $appId, array $data): void {
|
||||
if (empty($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->initiated) {
|
||||
$table->addRow(new TableSeparator());
|
||||
}
|
||||
$this->initiated = true;
|
||||
|
||||
$table->addRow(
|
||||
[
|
||||
new TableCell(
|
||||
$appId,
|
||||
[
|
||||
'colspan' => 2,
|
||||
'style' => new TableCellStyle(['cellFormat' => '<info>%s</info>'])
|
||||
]
|
||||
)
|
||||
]
|
||||
)->addRow(new TableSeparator());
|
||||
|
||||
/** @var MigrationAttribute[] $attributes */
|
||||
foreach($data as $migration => $attributes) {
|
||||
$attributesStr = [];
|
||||
foreach($attributes as $attribute) {
|
||||
$definition = '<info>' . $attribute->definition() . "</info>";
|
||||
$definition .= empty($attribute->getDescription()) ? '' : "\n " . $attribute->getDescription();
|
||||
$definition .= empty($attribute->getNotes()) ? '' : "\n <comment>" . implode("</comment>\n <comment>", $attribute->getNotes()) . '</comment>';
|
||||
$attributesStr[] = $definition;
|
||||
}
|
||||
$table->addRow([$migration, implode("\n", $attributesStr)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OC\Migration\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class AttributeException extends Exception {
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
namespace OC\Migration;
|
||||
|
||||
use OC\DB\Connection;
|
||||
use OC\DB\MigrationService;
|
||||
use OC\Migration\Exceptions\AttributeException;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\Migration\Attributes\GenericMigrationAttribute;
|
||||
use OCP\Migration\Attributes\MigrationAttribute;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Helps managing DB Migrations' Metadata
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class MetadataManager {
|
||||
public function __construct(
|
||||
private readonly IAppManager $appManager,
|
||||
private readonly Connection $connection,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* We get all migrations from an app (or 'core'), and
|
||||
* for each migration files we extract its attributes
|
||||
*
|
||||
* @param string $appId
|
||||
*
|
||||
* @return array<string, MigrationAttribute[]>
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function extractMigrationAttributes(string $appId): array {
|
||||
$ms = new MigrationService($appId, $this->connection);
|
||||
|
||||
$metadata = [];
|
||||
foreach($ms->getAvailableVersions() as $version) {
|
||||
$metadata[$version] = [];
|
||||
$class = new ReflectionClass($ms->createInstance($version));
|
||||
$attributes = $class->getAttributes();
|
||||
foreach ($attributes as $attribute) {
|
||||
$item = $attribute->newInstance();
|
||||
if ($item instanceof MigrationAttribute) {
|
||||
$metadata[$version][] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert direct data from release metadata into a list of Migrations' Attribute
|
||||
*
|
||||
* @param array<array-key, array<array-key, array>> $metadata
|
||||
* @param bool $filterKnownMigrations ignore metadata already done in local instance
|
||||
*
|
||||
* @return array{apps: array<array-key, array<string, MigrationAttribute[]>>, core: array<string, MigrationAttribute[]>}
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getMigrationsAttributesFromReleaseMetadata(
|
||||
array $metadata,
|
||||
bool $filterKnownMigrations = false
|
||||
): array {
|
||||
$appsAttributes = [];
|
||||
foreach (array_keys($metadata['apps']) as $appId) {
|
||||
if ($filterKnownMigrations && !$this->appManager->isInstalled($appId)) {
|
||||
continue; // if not interested and app is not installed
|
||||
}
|
||||
|
||||
$done = ($filterKnownMigrations) ? $this->getKnownMigrations($appId) : [];
|
||||
$appsAttributes[$appId] = $this->parseMigrations($metadata['apps'][$appId] ?? [], $done);
|
||||
}
|
||||
|
||||
$done = ($filterKnownMigrations) ? $this->getKnownMigrations('core') : [];
|
||||
return [
|
||||
'core' => $this->parseMigrations($metadata['core'] ?? [], $done),
|
||||
'apps' => $appsAttributes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* convert raw data to a list of MigrationAttribute
|
||||
*
|
||||
* @param array $migrations
|
||||
* @param array $ignoreMigrations
|
||||
*
|
||||
* @return array<string, MigrationAttribute[]>
|
||||
*/
|
||||
private function parseMigrations(array $migrations, array $ignoreMigrations = []): array {
|
||||
$parsed = [];
|
||||
foreach (array_keys($migrations) as $entry) {
|
||||
if (in_array($entry, $ignoreMigrations)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed[$entry] = [];
|
||||
foreach ($migrations[$entry] as $item) {
|
||||
try {
|
||||
$parsed[$entry][] = $this->createAttribute($item);
|
||||
} catch (AttributeException $e) {
|
||||
$this->logger->warning('exception while trying to create attribute', ['exception' => $e, 'item' => json_encode($item)]);
|
||||
$parsed[$entry][] = new GenericMigrationAttribute($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns migrations already done
|
||||
*
|
||||
* @param string $appId
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function getKnownMigrations(string $appId): array {
|
||||
$ms = new MigrationService($appId, $this->connection);
|
||||
return $ms->getMigratedVersions();
|
||||
}
|
||||
|
||||
/**
|
||||
* generate (deserialize) a MigrationAttribute from a serialized version
|
||||
*
|
||||
* @param array $item
|
||||
*
|
||||
* @return MigrationAttribute
|
||||
* @throws AttributeException
|
||||
*/
|
||||
private function createAttribute(array $item): MigrationAttribute {
|
||||
$class = $item['class'] ?? '';
|
||||
$namespace = 'OCP\Migration\Attributes\\';
|
||||
if (!str_starts_with($class, $namespace)
|
||||
|| !ctype_alpha(substr($class, strlen($namespace)))) {
|
||||
throw new AttributeException('class name does not looks valid');
|
||||
}
|
||||
|
||||
try {
|
||||
$attribute = new $class($item['table'] ?? '');
|
||||
return $attribute->import($item);
|
||||
} catch (\Error) {
|
||||
throw new AttributeException('cannot import Attribute');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OC\Updater\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class ReleaseMetadataException extends Exception {
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OC\Updater;
|
||||
|
||||
use Exception;
|
||||
use JsonException;
|
||||
use OC\Updater\Exceptions\ReleaseMetadataException;
|
||||
use OCP\Http\Client\IClientService;
|
||||
|
||||
/** retrieve releases metadata from official servers
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class ReleaseMetadata {
|
||||
public function __construct(
|
||||
private readonly IClientService $clientService,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns metadata based on release version
|
||||
*
|
||||
* - version is a stable release, metadata is downloaded from official releases folder
|
||||
* - version is not a table release, metadata is downloaded from official prereleases folder
|
||||
* - version is a major version (30, 31, 32, ...), latest metadata are downloaded
|
||||
*
|
||||
* @param string $version
|
||||
*
|
||||
* @return array
|
||||
* @throws ReleaseMetadataException
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getMetadata(string $version): array {
|
||||
if (!str_contains($version, '.')) {
|
||||
$url = 'https://download.nextcloud.com/server/releases/latest-' . $version . '.metadata';
|
||||
} else {
|
||||
[,,$minor] = explode('.', $version);
|
||||
if (ctype_digit($minor)) {
|
||||
$url = 'https://download.nextcloud.com/server/releases/nextcloud-' . $version . '.metadata';
|
||||
} else {
|
||||
$url = 'https://download.nextcloud.com/server/prereleases/nextcloud-' . $version . '.metadata';
|
||||
}
|
||||
}
|
||||
return $this->downloadMetadata($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* download Metadata from a link
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return array
|
||||
* @throws ReleaseMetadataException
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function downloadMetadata(string $url): array {
|
||||
$client = $this->clientService->newClient();
|
||||
try {
|
||||
$response = $client->get($url, [
|
||||
'timeout' => 10,
|
||||
'connect_timeout' => 10
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
throw new ReleaseMetadataException('could not reach metadata at ' . $url, previous: $e);
|
||||
}
|
||||
|
||||
try {
|
||||
return json_decode($response->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException) {
|
||||
throw new ReleaseMetadataException('remote document is not valid');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on new column creation
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class AddColumn extends ColumnMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
$type = is_null($this->getType()) ? '' : ' (' . $this->getType()->value . ')';
|
||||
return empty($this->getName()) ?
|
||||
'Addition of a new column' . $type . ' to table \'' . $this->getTable() . '\''
|
||||
: 'Addition of column \'' . $this->getName() . '\'' . $type . ' to table \'' . $this->getTable() . '\'';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on index creation
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class AddIndex extends IndexMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
$type = is_null($this->getType()) ? '' : ' (' . $this->getType()->value . ')';
|
||||
return 'Addition of a new index' . $type . ' to table \'' . $this->getTable() . '\'';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* generic class related to migration attribute about column changes
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class ColumnMigrationAttribute extends MigrationAttribute implements JsonSerializable {
|
||||
/**
|
||||
* @param string $table name of the database table
|
||||
* @param string $name name of the column
|
||||
* @param ColumnType|null $type type of the column
|
||||
* @param string $description description of the migration
|
||||
* @param array $notes notes about the migration/column
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
string $table,
|
||||
private string $name = '',
|
||||
private ?ColumnType $type = null,
|
||||
string $description = '',
|
||||
array $notes = [],
|
||||
) {
|
||||
parent::__construct($table, $description, $notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setName(string $name): self {
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ColumnType|null $type
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setType(?ColumnType $type): self {
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ColumnType|null
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getType(): ?ColumnType {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function import(array $data): self {
|
||||
parent::import($data);
|
||||
$this->setName($data['name'] ?? '');
|
||||
$this->setType(ColumnType::tryFrom($data['type'] ?? ''));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return array_merge(
|
||||
parent::jsonSerialize(),
|
||||
[
|
||||
'name' => $this->getName(),
|
||||
'type' => $this->getType() ?? '',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
/**
|
||||
* enum ColumnType based on OCP\DB\Types
|
||||
*
|
||||
* @see \OCP\DB\Types
|
||||
* @since 30.0.0
|
||||
*/
|
||||
enum ColumnType : string {
|
||||
/** @since 30.0.0 */
|
||||
case BIGINT = 'bigint';
|
||||
/** @since 30.0.0 */
|
||||
case BINARY = 'binary';
|
||||
/** @since 30.0.0 */
|
||||
case BLOB = 'blob';
|
||||
/** @since 30.0.0 */
|
||||
case BOOLEAN = 'boolean';
|
||||
/** @since 30.0.0 */
|
||||
case DATE = 'date';
|
||||
/** @since 30.0.0 */
|
||||
case DATETIME = 'datetime';
|
||||
/** @since 30.0.0 */
|
||||
case DECIMAL = 'decimal';
|
||||
/** @since 30.0.0 */
|
||||
case FLOAT = 'float';
|
||||
/** @since 30.0.0 */
|
||||
case INTEGER = 'integer';
|
||||
/** @since 30.0.0 */
|
||||
case SMALLINT = 'smallint';
|
||||
/** @since 30.0.0 */
|
||||
case STRING = 'string';
|
||||
/** @since 30.0.0 */
|
||||
case TEXT = 'text';
|
||||
/** @since 30.0.0 */
|
||||
case TIME = 'time';
|
||||
/** @since 30.0.0 */
|
||||
case JSON = 'json';
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on table creation
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class CreateTable extends TableMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
$definition = 'Creation of new table \'' . $this->getTable() . '\'';
|
||||
$definition .= empty($this->getColumns()) ? '' : ' with columns ' . implode(', ', $this->getColumns());
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on column drop
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class DropColumn extends ColumnMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
return empty($this->getName()) ?
|
||||
'Deletion of a column from table \'' . $this->getTable() . '\''
|
||||
: 'Deletion of column \'' . $this->getName() . '\' from table \'' . $this->getTable() . '\'';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on index drop
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class DropIndex extends IndexMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
return 'Deletion of an index from table \'' . $this->getTable() . '\'';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on table drop
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class DropTable extends TableMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
return 'Deletion of table \'' . $this->getTable() . '\'';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* generic entry, used to replace migration attribute not yet known in current version
|
||||
* but used in a future release
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class GenericMigrationAttribute extends MigrationAttribute implements JsonSerializable {
|
||||
/**
|
||||
* @param array $details
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $details = []
|
||||
) {
|
||||
parent::__construct(
|
||||
$details['table'] ?? '',
|
||||
$details['description'] ?? '',
|
||||
$details['notes'] ?? []
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
return json_encode($this->jsonSerialize(), JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return $this->details;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* generic class related to migration attribute about index changes
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class IndexMigrationAttribute extends MigrationAttribute implements JsonSerializable {
|
||||
/**
|
||||
* @param string $table name of the database table
|
||||
* @param IndexType|null $type type of the index
|
||||
* @param string $description description of the migration
|
||||
* @param array $notes notes abour the migration/index
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
string $table,
|
||||
private ?IndexType $type = null,
|
||||
string $description = '',
|
||||
array $notes = [],
|
||||
) {
|
||||
parent::__construct($table, $description, $notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IndexType|null $type
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setType(?IndexType $type): self {
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IndexType|null
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getType(): ?IndexType {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function import(array $data): self {
|
||||
parent::import($data);
|
||||
$this->setType(IndexType::tryFrom($data['type'] ?? ''));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return array_merge(
|
||||
parent::jsonSerialize(),
|
||||
[
|
||||
'type' => $this->getType() ?? '',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
/**
|
||||
* type of index
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
enum IndexType : string {
|
||||
/** @since 30.0.0 */
|
||||
case PRIMARY = 'primary';
|
||||
/** @since 30.0.0 */
|
||||
case INDEX = 'index';
|
||||
/** @since 30.0.0 */
|
||||
case UNIQUE = 'unique';
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class MigrationAttribute implements JsonSerializable {
|
||||
/**
|
||||
* @param string $table name of the database table
|
||||
* @param string $description description of the migration
|
||||
* @param array $notes notes about the migration
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
private string $table,
|
||||
private string $description = '',
|
||||
private array $notes = [],
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setTable(string $table): self {
|
||||
$this->table = $table;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getTable(): string {
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $description
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setDescription(string $description): self {
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getDescription(): string {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $notes
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setNotes(array $notes): self {
|
||||
$this->notes = $notes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getNotes(): array {
|
||||
return $this->notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
return json_encode($this->jsonSerialize(), JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return self
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function import(array $data): self {
|
||||
return $this->setDescription($data['description'] ?? '')
|
||||
->setNotes($data['notes'] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return [
|
||||
'class' => get_class($this),
|
||||
'table' => $this->getTable(),
|
||||
'description' => $this->getDescription(),
|
||||
'notes' => $this->getNotes()
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* attribute on column modification
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class ModifyColumn extends ColumnMigrationAttribute {
|
||||
/**
|
||||
* @return string
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function definition(): string {
|
||||
$type = is_null($this->getType()) ? '' : ' to ' . $this->getType()->value;
|
||||
return empty($this->getName()) ?
|
||||
'Modification of a column from table \'' . $this->getTable() . '\'' . $type
|
||||
: 'Modification of column \'' . $this->getName() . '\' from table \'' . $this->getTable() . '\'' . $type;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Migration\Attributes;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* generic class related to migration attribute about table changes
|
||||
*
|
||||
* @since 30.0.0
|
||||
*/
|
||||
class TableMigrationAttribute extends MigrationAttribute implements JsonSerializable {
|
||||
/**
|
||||
* @param string $table name of the database table
|
||||
* @param array $columns list of columns
|
||||
* @param string $description description of the migration
|
||||
* @param array $notes notes about the migration/table
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
string $table,
|
||||
private array $columns = [],
|
||||
string $description = '',
|
||||
array $notes = [],
|
||||
) {
|
||||
parent::__construct($table, $description, $notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $columns
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function setColumns(array $columns): self {
|
||||
$this->columns = $columns;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function getColumns(): array {
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function import(array $data): self {
|
||||
parent::import($data);
|
||||
$this->setColumns($data['columns'] ?? []);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 30.0.0
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return array_merge(
|
||||
parent::jsonSerialize(),
|
||||
[
|
||||
'columns' => $this->getColumns(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
namespace Test\Updater;
|
||||
|
||||
use OC\Updater\ReleaseMetadata;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class ReleaseMetadataTest extends \Test\TestCase {
|
||||
private IClientService| MockObject $clientService;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->clientService = $this->getMockBuilder(IClientService::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
public function testDownloadMetadata() {
|
||||
$client = $this->createMock(IClient::class);
|
||||
$response = $this->createMock(IResponse::class);
|
||||
$this->clientService->expects($this->once())
|
||||
->method('newClient')
|
||||
->with()
|
||||
->willReturn($client);
|
||||
$client->expects($this->once())
|
||||
->method('get')
|
||||
->willReturn($response);
|
||||
$response->expects($this->once())
|
||||
->method('getBody')
|
||||
->with()
|
||||
->willReturn($this->resultRequest());
|
||||
|
||||
|
||||
$releaseMetadata = new ReleaseMetadata($this->clientService);
|
||||
$this->assertSame($this->resultRequestArray(), $releaseMetadata->downloadMetadata('ouila'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getMetadataUrlProvider
|
||||
*
|
||||
* @param string $version
|
||||
* @param string $url
|
||||
*/
|
||||
public function testGetMetadata(string $version, string $url) {
|
||||
$client = $this->createMock(IClient::class);
|
||||
$response = $this->createMock(IResponse::class);
|
||||
$this->clientService->expects($this->once())
|
||||
->method('newClient')
|
||||
->with()
|
||||
->willReturn($client);
|
||||
$client->expects($this->once())
|
||||
->method('get')
|
||||
->with($url)
|
||||
->willReturn($response);
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getBody')
|
||||
->with()
|
||||
->willReturn('{}');
|
||||
|
||||
$releaseMetadata = new ReleaseMetadata($this->clientService);
|
||||
$releaseMetadata->getMetadata($version);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMetadataUrlProvider(): array {
|
||||
return [
|
||||
[
|
||||
'30.0.0',
|
||||
'https://download.nextcloud.com/server/releases/nextcloud-30.0.0.metadata'
|
||||
],
|
||||
[
|
||||
'30.0.0-beta1',
|
||||
'https://download.nextcloud.com/server/prereleases/nextcloud-30.0.0-beta1.metadata'
|
||||
],
|
||||
[
|
||||
'30',
|
||||
'https://download.nextcloud.com/server/releases/latest-30.metadata'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
private function resultRequest(): string {
|
||||
return json_encode($this->resultRequestArray());
|
||||
}
|
||||
|
||||
private function resultRequestArray(): array {
|
||||
return [
|
||||
'migrations' => [
|
||||
'core' => [],
|
||||
'apps' => [
|
||||
'testing' => [
|
||||
'30000Date20240102030405' => [
|
||||
'class' => 'OCP\\Migration\\Attributes\\DropTable',
|
||||
'table' => 'old_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'columns' => []
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\CreateTable',
|
||||
'table' => 'new_table',
|
||||
'description' => 'Table is used to store things, but also to get more things',
|
||||
'notes' => [
|
||||
'this is a notice',
|
||||
'and another one, if really needed'
|
||||
],
|
||||
'columns' => []
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\AddColumn',
|
||||
'table' => 'my_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => '',
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\AddColumn',
|
||||
'table' => 'my_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => 'another_field',
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\AddColumn',
|
||||
'table' => 'other_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => 'last_one',
|
||||
'type' => 'date'
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\AddIndex',
|
||||
'table' => 'my_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\AddIndex',
|
||||
'table' => 'my_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'type' => 'primary'
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\DropColumn',
|
||||
'table' => 'other_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => '',
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\DropColumn',
|
||||
'table' => 'other_table',
|
||||
'description' => 'field is not used anymore and replaced by \'last_one\'',
|
||||
'notes' => [],
|
||||
'name' => 'old_column',
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\DropIndex',
|
||||
'table' => 'other_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\ModifyColumn',
|
||||
'table' => 'other_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => '',
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\ModifyColumn',
|
||||
'table' => 'other_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => 'this_field',
|
||||
'type' => ''
|
||||
],
|
||||
[
|
||||
'class' => 'OCP\\Migration\\Attributes\\ModifyColumn',
|
||||
'table' => 'other_table',
|
||||
'description' => '',
|
||||
'notes' => [],
|
||||
'name' => 'this_field',
|
||||
'type' => 'bigint'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue