forked from owncloud/music
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix migration on NC from Music app older than v1.0.0
When defining the DB schema for Nextcloud was moved to use the migrations mechanism in v1.2.1 (commit 6982d91), a problem was introduced: The migration worked only either on a clean database (no earlier versions of Music installed) or on v1.0.0 or newer. Installing over any v0.x.y got broken. This was because the auto-generated migration script Version010200Date20210513171803 newer altered the DB schema of existing tables; it just created tables which were missing. The not so well-working migration script has now been replaced with the hand-written Version010000Date20210903000000. This script checks separately that each needed column exists in the database and creates the missing ones. It also removes couple of obsolete columns (removed over the years) if those are still present in the database. This new script should be able to migrate the database from any version starting from v0.4.0 to the v1.0.0 level. Most of these versions have not been tested, though. refs owncloud#889 refs owncloud#883
- Loading branch information
Showing
2 changed files
with
273 additions
and
401 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OCA\Music\Migration; | ||
|
||
use Closure; | ||
use OCP\DB\ISchemaWrapper; | ||
use OCP\Migration\SimpleMigrationStep; | ||
use OCP\Migration\IOutput; | ||
|
||
/** | ||
* Migrate the DB schema to Music v1.0.0 level from any previous version starting from v0.4.0 | ||
*/ | ||
class Version010000Date20210903000000 extends SimpleMigrationStep { | ||
|
||
/** | ||
* @param IOutput $output | ||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` | ||
* @param array $options | ||
*/ | ||
public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { | ||
} | ||
|
||
/** | ||
* @param IOutput $output | ||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` | ||
* @param array $options | ||
* @return null|ISchemaWrapper | ||
*/ | ||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { | ||
/** @var ISchemaWrapper $schema */ | ||
$schema = $schemaClosure(); | ||
|
||
$this->migrateMusicArtists($schema); | ||
$this->migrateMusicAlbums($schema); | ||
$this->migrateMusicTracks($schema); | ||
$this->migrateMusicPlaylists($schema); | ||
$this->migrateMusicGenres($schema); | ||
$this->migrateMusicRadioStations($schema); | ||
$this->migrateMusicAmpacheSessions($schema); | ||
$this->migrateAmpacheUsers($schema); | ||
$this->migrateMusicCache($schema); | ||
$this->migrateMusicBookmarks($schema); | ||
|
||
return $schema; | ||
} | ||
|
||
/** | ||
* @param IOutput $output | ||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` | ||
* @param array $options | ||
*/ | ||
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { | ||
} | ||
|
||
private function migrateMusicArtists(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_artists'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'name', 'string', ['notnull' => false, 'length' => 256] ], | ||
[ 'cover_file_id', 'bigint', ['notnull' => false,'length' => 10] ], | ||
[ 'mbid', 'string', ['notnull' => false, 'length' => 36] ], | ||
[ 'hash', 'string', ['notnull' => true, 'length' => 32] ], | ||
[ 'starred', 'datetime', ['notnull' => false] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ] | ||
]); | ||
$this->dropObsoleteColumn($table, 'image'); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setUniqueIndex($table, 'user_id_hash_idx', ['user_id', 'hash']); | ||
} | ||
|
||
private function migrateMusicAlbums(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_albums'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'name', 'string', ['notnull' => false, 'length' => 256] ], | ||
[ 'cover_file_id', 'bigint', ['notnull' => false, 'length' => 10] ], | ||
[ 'mbid', 'string', ['notnull' => false, 'length' => 36] ], | ||
[ 'disk', 'integer', ['notnull' => false, 'unsigned' => true] ], | ||
[ 'mbid_group', 'string', ['notnull' => false, 'length' => 36] ], | ||
[ 'album_artist_id', 'integer', ['notnull' => false] ], | ||
[ 'hash', 'string', ['notnull' => true, 'length' => 32] ], | ||
[ 'starred', 'datetime', ['notnull' => false] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ] | ||
]); | ||
$this->dropObsoleteColumn($table, 'year'); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setIndex($table, 'ma_cover_file_id_idx', ['cover_file_id']); | ||
$this->setIndex($table, 'ma_album_artist_id_idx', ['album_artist_id']); | ||
$this->setUniqueIndex($table, 'ma_user_id_hash_idx', ['user_id', 'hash']); | ||
} | ||
|
||
private function migrateMusicTracks(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_tracks'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true, ] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64, ] ], | ||
[ 'title', 'string', ['notnull' => true, 'length' => 256, ] ], | ||
[ 'number', 'integer', ['notnull' => false, 'unsigned' => true] ], | ||
[ 'disk', 'integer', ['notnull' => false, 'unsigned' => true] ], | ||
[ 'year', 'integer', ['notnull' => false, 'unsigned' => true] ], | ||
[ 'artist_id', 'integer', ['notnull' => false] ], | ||
[ 'album_id', 'integer', ['notnull' => false] ], | ||
[ 'length', 'integer', ['notnull' => false, 'unsigned' => true] ], | ||
[ 'file_id', 'bigint', ['notnull' => true, 'length' => 10] ], | ||
[ 'bitrate', 'integer', ['notnull' => false, 'unsigned' => true] ], | ||
[ 'mimetype', 'string', ['notnull' => true, 'length' => 256] ], | ||
[ 'mbid', 'string', ['notnull' => false, 'length' => 36] ], | ||
[ 'starred', 'datetime', ['notnull' => false] ], | ||
[ 'genre_id', 'integer', ['notnull' => false, 'unsigned' => true, ] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setIndex($table, 'music_tracks_artist_id_idx', ['artist_id']); | ||
$this->setIndex($table, 'music_tracks_album_id_idx', ['album_id']); | ||
$this->setIndex($table, 'music_tracks_user_id_idx', ['user_id']); | ||
$this->setUniqueIndex($table, 'music_tracks_file_user_id_idx', ['file_id', 'user_id']); | ||
} | ||
|
||
private function migrateMusicPlaylists(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_playlists'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'name', 'string', ['notnull' => false, 'length' => 256] ], | ||
[ 'track_ids', 'text', ['notnull' => false] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ], | ||
[ 'comment', 'string', ['notnull' => false, 'length' => 256] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
} | ||
|
||
private function migrateMusicGenres(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_genres'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'name', 'string', ['notnull' => false, 'length' => 64] ], | ||
[ 'lower_name', 'string', ['notnull' => false, 'length' => 64] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setUniqueIndex($table, 'mg_lower_name_user_id_idx', ['lower_name', 'user_id']); | ||
} | ||
|
||
private function migrateMusicRadioStations(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_radio_stations'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'name', 'string', ['notnull' => false, 'length' => 256] ], | ||
[ 'stream_url', 'string', ['notnull' => true, 'length' => 2048] ], | ||
[ 'home_url', 'string', ['notnull' => false, 'length' => 2048] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
} | ||
|
||
private function migrateMusicAmpacheSessions(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_ampache_sessions'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'token', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'expiry', 'integer', ['notnull' => true,'unsigned' => true] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setUniqueIndex($table, 'music_ampache_sessions_index', ['token']); | ||
} | ||
|
||
private function migrateAmpacheUsers(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_ampache_users'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'length' => 4] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'description', 'string', ['notnull' => false, 'length' => 64] ], | ||
[ 'hash', 'string', ['notnull' => true, 'length' => 64] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setUniqueIndex($table, 'music_ampache_users_index', ['hash', 'user_id']); | ||
} | ||
|
||
private function migrateMusicCache(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_cache'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'key', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'data', 'text', ['notnull' => false] ], | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setUniqueIndex($table, 'music_cache_index', ['user_id', 'key']); | ||
} | ||
|
||
private function migrateMusicBookmarks(ISchemaWrapper $schema) { | ||
$table = $this->getOrCreateTable($schema, 'music_bookmarks'); | ||
$this->setColumns($table, [ | ||
[ 'id', 'integer', ['autoincrement' => true, 'notnull' => true, 'unsigned' => true] ], | ||
[ 'user_id', 'string', ['notnull' => true, 'length' => 64] ], | ||
[ 'track_id', 'integer', ['notnull' => true] ], | ||
[ 'position', 'integer', ['notnull' => true] ], | ||
[ 'comment', 'string', ['notnull' => false, 'length' => 256] ], | ||
[ 'created', 'datetime', ['notnull' => false] ], | ||
[ 'updated', 'datetime', ['notnull' => false] ] | ||
]); | ||
|
||
$this->setPrimaryKey($table, ['id']); | ||
$this->setUniqueIndex($table, 'music_bookmarks_user_track', ['user_id', 'track_id']); | ||
} | ||
|
||
private function getOrCreateTable(ISchemaWrapper $schema, string $name) { | ||
if (!$schema->hasTable($name)) { | ||
return $schema->createTable($name); | ||
} else { | ||
return $schema->getTable($name); | ||
} | ||
} | ||
|
||
private function setColumn($table, string $name, string $type, array $args) { | ||
if (!$table->hasColumn($name)) { | ||
$table->addColumn($name, $type, $args); | ||
} | ||
} | ||
|
||
private function setColumns($table, array $nameTypeArgsPerCol) { | ||
foreach ($nameTypeArgsPerCol as $nameTypeArgs) { | ||
list($name, $type, $args) = $nameTypeArgs; | ||
$this->setColumn($table, $name, $type, $args); | ||
} | ||
} | ||
|
||
private function dropObsoleteColumn($table, string $name) { | ||
if ($table->hasColumn($name)) { | ||
$table->dropColumn($name); | ||
} | ||
} | ||
|
||
private function setIndex($table, string $name, array $columns) { | ||
if (!$table->hasIndex($name)) { | ||
$table->addIndex($columns, $name); | ||
} | ||
} | ||
|
||
private function setUniqueIndex($table, string $name, array $columns) { | ||
if (!$table->hasIndex($name)) { | ||
$table->addUniqueIndex($columns, $name); | ||
} | ||
} | ||
|
||
private function setPrimaryKey($table, array $columns) { | ||
if (!$table->hasPrimaryKey()) { | ||
$table->setPrimaryKey($columns); | ||
} | ||
} | ||
} |
Oops, something went wrong.