mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-05-31 15:51:32 +00:00
Merge c195550209 into c009db9f28
This commit is contained in:
commit
57e2ef0a54
2 changed files with 88 additions and 3 deletions
|
|
@ -966,6 +966,20 @@ WHERE EXISTS (
|
||||||
return `unaccent(${value})`
|
return `unaccent(${value})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an expression that strips punctuation the older in-memory search ignored.
|
||||||
|
*
|
||||||
|
* @param {string} expression
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
stripPunctuation(expression) {
|
||||||
|
const punctuationChars = ["'", '.', '`', '"', ',']
|
||||||
|
punctuationChars.forEach((char) => {
|
||||||
|
expression = `replace(${expression}, ${this.sequelize.escape(char)}, '')`
|
||||||
|
})
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the text query.
|
* Initialize the text query.
|
||||||
*
|
*
|
||||||
|
|
@ -983,15 +997,17 @@ WHERE EXISTS (
|
||||||
* Get match expression for the specified column.
|
* Get match expression for the specified column.
|
||||||
* If the query contains accents, match against the column as-is (case-insensitive exact match).
|
* If the query contains accents, match against the column as-is (case-insensitive exact match).
|
||||||
* otherwise match against a normalized column (case-insensitive match with accents removed).
|
* otherwise match against a normalized column (case-insensitive match with accents removed).
|
||||||
|
* Punctuation is stripped from both sides in all cases.
|
||||||
*
|
*
|
||||||
* @param {string} column
|
* @param {string} column
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
matchExpression(column) {
|
matchExpression(column) {
|
||||||
const pattern = this.sequelize.escape(`%${this.query}%`)
|
const queryExpr = this.stripPunctuation(this.sequelize.escape(this.query))
|
||||||
if (!this.supportsUnaccent) return `${column} LIKE ${pattern}`
|
const pattern = `'%' || ${queryExpr} || '%'`
|
||||||
|
if (!this.supportsUnaccent) return `${this.stripPunctuation(column)} LIKE ${pattern}`
|
||||||
const normalizedColumn = this.hasAccents ? column : this.normalize(column)
|
const normalizedColumn = this.hasAccents ? column : this.normalize(column)
|
||||||
return `${normalizedColumn} LIKE ${pattern}`
|
return `${this.stripPunctuation(normalizedColumn)} LIKE ${pattern}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
69
test/server/utils/queries/libraryItemsBookFilters.test.js
Normal file
69
test/server/utils/queries/libraryItemsBookFilters.test.js
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
const { expect } = require('chai')
|
||||||
|
const { Sequelize } = require('sequelize')
|
||||||
|
|
||||||
|
const Database = require('../../../../server/Database')
|
||||||
|
const libraryItemsBookFilters = require('../../../../server/utils/queries/libraryItemsBookFilters')
|
||||||
|
|
||||||
|
describe('libraryItemsBookFilters.search', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
global.ServerSettings = {}
|
||||||
|
Database.sequelize = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
||||||
|
Database.sequelize.uppercaseFirst = (str) => (str ? `${str[0].toUpperCase()}${str.substr(1)}` : '')
|
||||||
|
Database.supportsUnaccent = false
|
||||||
|
await Database.buildModels()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await Database.sequelize.sync({ force: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('matches titles when the query omits commas', async () => {
|
||||||
|
const library = await Database.libraryModel.create({ name: 'Test Library', mediaType: 'book' })
|
||||||
|
const libraryFolder = await Database.libraryFolderModel.create({ path: '/test', libraryId: library.id })
|
||||||
|
const book = await Database.bookModel.create({
|
||||||
|
title: 'And Now, Back to You',
|
||||||
|
audioFiles: [],
|
||||||
|
tags: [],
|
||||||
|
narrators: [],
|
||||||
|
genres: [],
|
||||||
|
chapters: []
|
||||||
|
})
|
||||||
|
await Database.libraryItemModel.create({
|
||||||
|
libraryFiles: [],
|
||||||
|
mediaId: book.id,
|
||||||
|
mediaType: 'book',
|
||||||
|
libraryId: library.id,
|
||||||
|
libraryFolderId: libraryFolder.id
|
||||||
|
})
|
||||||
|
|
||||||
|
const results = await libraryItemsBookFilters.search(null, library, 'And Now Back to You', 10, 0)
|
||||||
|
|
||||||
|
expect(results.book).to.have.length(1)
|
||||||
|
expect(results.book[0].libraryItem.media.metadata.title).to.equal('And Now, Back to You')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('matches titles when the query omits apostrophes', async () => {
|
||||||
|
const library = await Database.libraryModel.create({ name: 'Test Library', mediaType: 'book' })
|
||||||
|
const libraryFolder = await Database.libraryFolderModel.create({ path: '/test', libraryId: library.id })
|
||||||
|
const book = await Database.bookModel.create({
|
||||||
|
title: "Don't Panic",
|
||||||
|
audioFiles: [],
|
||||||
|
tags: [],
|
||||||
|
narrators: [],
|
||||||
|
genres: [],
|
||||||
|
chapters: []
|
||||||
|
})
|
||||||
|
await Database.libraryItemModel.create({
|
||||||
|
libraryFiles: [],
|
||||||
|
mediaId: book.id,
|
||||||
|
mediaType: 'book',
|
||||||
|
libraryId: library.id,
|
||||||
|
libraryFolderId: libraryFolder.id
|
||||||
|
})
|
||||||
|
|
||||||
|
const results = await libraryItemsBookFilters.search(null, library, 'Dont Panic', 10, 0)
|
||||||
|
|
||||||
|
expect(results.book).to.have.length(1)
|
||||||
|
expect(results.book[0].libraryItem.media.metadata.title).to.equal("Don't Panic")
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue