diff --git a/server/migrations/changelog.md b/server/migrations/changelog.md index 92be2cd5b0..3623300f4c 100644 --- a/server/migrations/changelog.md +++ b/server/migrations/changelog.md @@ -6,3 +6,4 @@ Please add a record of every database migration that you create to this file. Th | -------------- | ---------------------------- | ------------------------------------------------------------------------------------ | | v2.15.0 | v2.15.0-series-column-unique | Series must have unique names in the same library | | v2.15.1 | v2.15.1-reindex-nocase | Fix potential db corruption issues due to bad sqlite extension introduced in v2.12.0 | +| v2.15.2 | v2.15.2-index-creation | Creates author, series, and podcast episode indexes | diff --git a/server/migrations/v2.15.2-index-creation.js b/server/migrations/v2.15.2-index-creation.js new file mode 100644 index 0000000000..f1302dd26b --- /dev/null +++ b/server/migrations/v2.15.2-index-creation.js @@ -0,0 +1,93 @@ +/** + * @typedef MigrationContext + * @property {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object. + * @property {import('../Logger')} logger - a Logger object. + * + * @typedef MigrationOptions + * @property {MigrationContext} context - an object containing the migration context. + */ + +/** + * This upward migration script adds indexes to speed up queries on the `BookAuthor`, `BookSeries`, and `podcastEpisodes` tables. + * + * @param {MigrationOptions} options - an object containing the migration context. + * @returns {Promise} - A promise that resolves when the migration is complete. + */ +async function up({ context: { queryInterface, logger } }) { + // Upwards migration script + logger.info('[2.15.2 migration] UPGRADE BEGIN: 2.15.2-index-creation') + + // Create index for bookAuthors + logger.info('[2.15.2 migration] Creating index for bookAuthors') + const bookAuthorsIndexes = await queryInterface.showIndex('bookAuthors') + if (!bookAuthorsIndexes.some((index) => index.name === 'bookAuthor_authorId')) { + await queryInterface.addIndex('bookAuthors', ['authorId'], { + name: 'bookAuthor_authorId' + }) + } else { + logger.info('[2.15.2 migration] Index bookAuthor_authorId already exists') + } + + // Create index for bookSeries + logger.info('[2.15.2 migration] Creating index for bookSeries') + const bookSeriesIndexes = await queryInterface.showIndex('bookSeries') + if (!bookSeriesIndexes.some((index) => index.name === 'bookSeries_seriesId')) { + await queryInterface.addIndex('bookSeries', ['seriesId'], { + name: 'bookSeries_seriesId' + }) + } else { + logger.info('[2.15.2 migration] Index bookSeries_seriesId already exists') + } + + // Delete existing podcastEpisode index + logger.info('[2.15.2 migration] Deleting existing podcastEpisode index') + await queryInterface.removeIndex('podcastEpisodes', 'podcast_episodes_created_at') + + // Create index for podcastEpisode and createdAt + logger.info('[2.15.2 migration] Creating index for podcastEpisode and createdAt') + const podcastEpisodesIndexes = await queryInterface.showIndex('podcastEpisodes') + if (!podcastEpisodesIndexes.some((index) => index.name === 'podcastEpisode_createdAt_podcastId')) { + await queryInterface.addIndex('podcastEpisodes', ['createdAt', 'podcastId'], { + name: 'podcastEpisode_createdAt_podcastId' + }) + } else { + logger.info('[2.15.2 migration] Index podcastEpisode_createdAt_podcastId already exists') + } + + // Completed migration + logger.info('[2.15.2 migration] UPGRADE END: 2.15.2-index-creation') +} + +/** + * This downward migration script removes the newly created indexes and re-adds the old index on the `podcastEpisodes` table. + * + * @param {MigrationOptions} options - an object containing the migration context. + * @returns {Promise} - A promise that resolves when the migration is complete. + */ +async function down({ context: { queryInterface, logger } }) { + // Downward migration script + logger.info('[2.15.2 migration] DOWNGRADE BEGIN: 2.15.2-index-creation') + + // Remove index for bookAuthors + logger.info('[2.15.2 migration] Removing index for bookAuthors') + await queryInterface.removeIndex('bookAuthors', 'bookAuthor_authorId') + + // Remove index for bookSeries + logger.info('[2.15.2 migration] Removing index for bookSeries') + await queryInterface.removeIndex('bookSeries', 'bookSeries_seriesId') + + // Delete existing podcastEpisode index + logger.info('[2.15.2 migration] Deleting existing podcastEpisode index') + await queryInterface.removeIndex('podcastEpisodes', 'podcastEpisode_createdAt_podcastId') + + // Create index for podcastEpisode and createdAt + logger.info('[2.15.2 migration] Creating original index for podcastEpisode createdAt') + await queryInterface.addIndex('podcastEpisodes', ['createdAt'], { + name: 'podcast_episodes_created_at' + }) + + // Finished migration + logger.info('[2.15.2 migration] DOWNGRADE END: 2.15.2-index-creation') +} + +module.exports = { up, down } diff --git a/server/models/BookAuthor.js b/server/models/BookAuthor.js index 8e09367161..d7d65728e2 100644 --- a/server/models/BookAuthor.js +++ b/server/models/BookAuthor.js @@ -54,7 +54,13 @@ class BookAuthor extends Model { sequelize, modelName: 'bookAuthor', timestamps: true, - updatedAt: false + updatedAt: false, + indexes: [ + { + name: 'bookAuthor_authorId', + fields: ['authorId'] + } + ] } ) diff --git a/server/models/BookSeries.js b/server/models/BookSeries.js index fad547181c..31eccb9fa3 100644 --- a/server/models/BookSeries.js +++ b/server/models/BookSeries.js @@ -43,7 +43,13 @@ class BookSeries extends Model { sequelize, modelName: 'bookSeries', timestamps: true, - updatedAt: false + updatedAt: false, + indexes: [ + { + name: 'bookSeries_seriesId', + fields: ['seriesId'] + } + ] } ) diff --git a/server/models/PodcastEpisode.js b/server/models/PodcastEpisode.js index 1707fbd5f1..1f99361ab7 100644 --- a/server/models/PodcastEpisode.js +++ b/server/models/PodcastEpisode.js @@ -157,7 +157,8 @@ class PodcastEpisode extends Model { modelName: 'podcastEpisode', indexes: [ { - fields: ['createdAt'] + name: 'podcastEpisode_createdAt_podcastId', + fields: ['createdAt', 'podcastId'] } ] }