diff --git a/migrations/20241025174046_actors_avatars.js b/migrations/20241025174046_actors_avatars.js new file mode 100644 index 00000000..32132e81 --- /dev/null +++ b/migrations/20241025174046_actors_avatars.js @@ -0,0 +1,75 @@ +exports.up = async function(knex) { + // restore avatars in table in case of rollback and rerun + const avatars = await knex('actors_avatars') + .select('actors_avatars.*', 'actors_profiles.actor_id') + .leftJoin('actors_profiles', 'actors_profiles.id', 'actors_avatars.profile_id'); + + await knex('actors_avatars').delete(); + + await knex.schema.alterTable('actors_avatars', (table) => { + table.integer('profile_id') + .nullable() + .alter(); + + table.integer('actor_id') + .notNullable() + .references('id') + .inTable('actors'); + + table.datetime('created_at') + .notNullable() + .defaultTo(knex.fn.now()); + + table.dropUnique('profile_id'); + table.unique(['profile_id', 'media_id']); + }); + + await knex.schema.alterTable('media', (table) => { + // actor avatars often retain the same URL when updated, handle URL-deduping in app code + table.dropUnique('source'); + table.string('source_version'); // usually etag + }); + + await knex.raw('CREATE UNIQUE INDEX unique_main_avatars ON actors_avatars (actor_id) WHERE (profile_id IS NULL);'); + + if (avatars.length > 0) { + await knex('actors_avatars').insert(avatars); + } + + const profiles = await knex('actors_profiles') + .select('id', 'actor_id', 'avatar_media_id') + .whereNotNull('avatar_media_id'); + + await knex('actors_avatars') + .insert(profiles.map((profile) => ({ + actor_id: profile.actor_id, + profile_id: profile.id, + media_id: profile.avatar_media_id, + }))) + .onConflict() + .ignore(); +}; + +exports.down = async function(knex) { + // no need to delete all entries, only the ones incompatible with the old scheme + await knex('actors_avatars') + .whereNull('profile_id') + .delete(); + + await knex.schema.alterTable('actors_avatars', (table) => { + table.integer('profile_id') + .notNullable() + .alter(); + + table.dropColumn('actor_id'); + table.dropColumn('created_at'); + + table.unique('profile_id'); + table.dropUnique(['profile_id', 'media_id']); + }); + + await knex.schema.alterTable('media', (table) => { + table.dropColumn('source_version'); + table.unique('source'); + }); +};