mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-08-02 22:51:45 +00:00
harden migration index handling for postgres replays
This commit is contained in:
parent
80d59dad93
commit
ec5892dfe9
3 changed files with 79 additions and 8 deletions
|
|
@ -28,7 +28,12 @@ async function up({ context: { queryInterface, logger } }) {
|
||||||
|
|
||||||
// Check if the unique index already exists
|
// Check if the unique index already exists
|
||||||
const seriesIndexes = await queryInterface.showIndex('Series')
|
const seriesIndexes = await queryInterface.showIndex('Series')
|
||||||
if (seriesIndexes.some((index) => index.name === 'unique_series_name_per_library')) {
|
if (
|
||||||
|
seriesIndexes.some((index) => {
|
||||||
|
const indexName = index?.name || index?.indexName || ''
|
||||||
|
return String(indexName).toLowerCase() === 'unique_series_name_per_library'
|
||||||
|
})
|
||||||
|
) {
|
||||||
logger.info('[2.15.0 migration] Unique index on Series.name and Series.libraryId already exists')
|
logger.info('[2.15.0 migration] Unique index on Series.name and Series.libraryId already exists')
|
||||||
logger.info('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique ')
|
logger.info('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique ')
|
||||||
return
|
return
|
||||||
|
|
@ -185,11 +190,20 @@ async function up({ context: { queryInterface, logger } }) {
|
||||||
logger.info(`[2.15.0 migration] Deduplication complete`)
|
logger.info(`[2.15.0 migration] Deduplication complete`)
|
||||||
|
|
||||||
// Create a unique index based on the name and library ID for the `Series` table
|
// Create a unique index based on the name and library ID for the `Series` table
|
||||||
await queryInterface.addIndex('Series', ['name', 'libraryId'], {
|
try {
|
||||||
unique: true,
|
await queryInterface.addIndex('Series', ['name', 'libraryId'], {
|
||||||
name: 'unique_series_name_per_library'
|
unique: true,
|
||||||
})
|
name: 'unique_series_name_per_library'
|
||||||
logger.info('[2.15.0 migration] Added unique index on Series.name and Series.libraryId')
|
})
|
||||||
|
logger.info('[2.15.0 migration] Added unique index on Series.name and Series.libraryId')
|
||||||
|
} catch (error) {
|
||||||
|
const alreadyExists =
|
||||||
|
(error?.name === 'SequelizeDatabaseError' && /already exists/i.test(error?.message || '')) ||
|
||||||
|
error?.original?.code === '42P07'
|
||||||
|
if (!alreadyExists) throw error
|
||||||
|
|
||||||
|
logger.info('[2.15.0 migration] Unique index on Series.name and Series.libraryId already exists')
|
||||||
|
}
|
||||||
|
|
||||||
logger.info('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique ')
|
logger.info('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique ')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ async function up({ context: { queryInterface, logger } }) {
|
||||||
|
|
||||||
// Delete existing podcastEpisode index
|
// Delete existing podcastEpisode index
|
||||||
logger.info('[2.15.2 migration] Deleting existing podcastEpisode index')
|
logger.info('[2.15.2 migration] Deleting existing podcastEpisode index')
|
||||||
await queryInterface.removeIndex('podcastEpisodes', 'podcast_episodes_created_at')
|
await removeIndexIfExists(queryInterface, 'podcastEpisodes', 'podcast_episodes_created_at', logger)
|
||||||
|
|
||||||
// Create index for podcastEpisode and createdAt
|
// Create index for podcastEpisode and createdAt
|
||||||
logger.info('[2.15.2 migration] Creating index for podcastEpisode and createdAt')
|
logger.info('[2.15.2 migration] Creating index for podcastEpisode and createdAt')
|
||||||
|
|
@ -78,7 +78,7 @@ async function down({ context: { queryInterface, logger } }) {
|
||||||
|
|
||||||
// Delete existing podcastEpisode index
|
// Delete existing podcastEpisode index
|
||||||
logger.info('[2.15.2 migration] Deleting existing podcastEpisode index')
|
logger.info('[2.15.2 migration] Deleting existing podcastEpisode index')
|
||||||
await queryInterface.removeIndex('podcastEpisodes', 'podcastEpisode_createdAt_podcastId')
|
await removeIndexIfExists(queryInterface, 'podcastEpisodes', 'podcastEpisode_createdAt_podcastId', logger)
|
||||||
|
|
||||||
// Create index for podcastEpisode and createdAt
|
// Create index for podcastEpisode and createdAt
|
||||||
logger.info('[2.15.2 migration] Creating original index for podcastEpisode createdAt')
|
logger.info('[2.15.2 migration] Creating original index for podcastEpisode createdAt')
|
||||||
|
|
@ -91,3 +91,15 @@ async function down({ context: { queryInterface, logger } }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { up, down }
|
module.exports = { up, down }
|
||||||
|
|
||||||
|
async function removeIndexIfExists(queryInterface, tableName, indexName, logger) {
|
||||||
|
const indexes = await queryInterface.showIndex(tableName)
|
||||||
|
const hasIndex = indexes.some((index) => String(index?.name || index?.indexName || '').toLowerCase() === indexName.toLowerCase())
|
||||||
|
|
||||||
|
if (!hasIndex) {
|
||||||
|
logger.info(`[2.15.2 migration] Index ${indexName} does not exist, skipping removeIndex`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryInterface.removeIndex(tableName, indexName)
|
||||||
|
}
|
||||||
|
|
|
||||||
45
test/server/migrations/v2.15.2-index-creation.test.js
Normal file
45
test/server/migrations/v2.15.2-index-creation.test.js
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
const { expect } = require('chai')
|
||||||
|
const { Sequelize, DataTypes } = require('sequelize')
|
||||||
|
|
||||||
|
const Logger = require('../../../server/Logger')
|
||||||
|
const { up, down } = require('../../../server/migrations/v2.15.2-index-creation')
|
||||||
|
|
||||||
|
describe('migration-v2.15.2-index-creation', () => {
|
||||||
|
let sequelize
|
||||||
|
let queryInterface
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
sequelize = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
||||||
|
queryInterface = sequelize.getQueryInterface()
|
||||||
|
|
||||||
|
await queryInterface.createTable('bookAuthors', {
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true },
|
||||||
|
authorId: { type: DataTypes.INTEGER }
|
||||||
|
})
|
||||||
|
|
||||||
|
await queryInterface.createTable('bookSeries', {
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true },
|
||||||
|
seriesId: { type: DataTypes.INTEGER }
|
||||||
|
})
|
||||||
|
|
||||||
|
await queryInterface.createTable('podcastEpisodes', {
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true },
|
||||||
|
createdAt: { type: DataTypes.DATE },
|
||||||
|
podcastId: { type: DataTypes.INTEGER }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('up should succeed when legacy podcast index is missing', async () => {
|
||||||
|
await up({ context: { queryInterface, logger: Logger } })
|
||||||
|
|
||||||
|
const indexes = await queryInterface.showIndex('podcastEpisodes')
|
||||||
|
expect(indexes.some((index) => index.name === 'podcastEpisode_createdAt_podcastId')).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('down should succeed when new podcast index is missing', async () => {
|
||||||
|
await down({ context: { queryInterface, logger: Logger } })
|
||||||
|
|
||||||
|
const indexes = await queryInterface.showIndex('podcastEpisodes')
|
||||||
|
expect(indexes.some((index) => index.name === 'podcast_episodes_created_at')).to.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue