diff --git a/src/backend/model/database/sql/PreviewManager.ts b/src/backend/model/database/sql/PreviewManager.ts index 0e4c857b..36f07977 100644 --- a/src/backend/model/database/sql/PreviewManager.ts +++ b/src/backend/model/database/sql/PreviewManager.ts @@ -94,7 +94,8 @@ export class PreviewManager implements IPreviewManager { public async getAlbumPreview(album: { searchQuery: SearchQueryDTO }): Promise { - const albumQuery: Brackets = await (ObjectManagers.getInstance().SearchManager as ISQLSearchManager).prepareAndBuildWhereQuery(album.searchQuery); + const albumQuery: Brackets = await (ObjectManagers.getInstance().SearchManager as ISQLSearchManager) + .prepareAndBuildWhereQuery(album.searchQuery); const connection = await SQLConnection.getConnection(); const previewQuery = (): SelectQueryBuilder => { @@ -111,9 +112,10 @@ export class PreviewManager implements IPreviewManager { let previewMedia = null; if (Config.Server.Preview.SearchQuery && !Utils.equalsFilter(Config.Server.Preview.SearchQuery, {type: SearchQueryTypes.any_text, text: ''} as TextSearch)) { + const previewFilterQuery = await (ObjectManagers.getInstance().SearchManager as ISQLSearchManager) + .prepareAndBuildWhereQuery(Config.Server.Preview.SearchQuery); previewMedia = await previewQuery() - .andWhere(await (ObjectManagers.getInstance().SearchManager as ISQLSearchManager) - .prepareAndBuildWhereQuery(Config.Server.Preview.SearchQuery)) + .andWhere(previewFilterQuery) .limit(1) .getOne(); } diff --git a/src/backend/model/database/sql/SearchManager.ts b/src/backend/model/database/sql/SearchManager.ts index 1a3a1c2b..d4e2e677 100644 --- a/src/backend/model/database/sql/SearchManager.ts +++ b/src/backend/model/database/sql/SearchManager.ts @@ -44,6 +44,8 @@ export class SearchManager implements ISQLSearchManager { 'CONCAT(\'[\' , GROUP_CONCAT( \'{"name": "\' , person.name , \'", "box": {"top":\' , faces.box.top , \', "left":\' , faces.box.left , \', "height":\' , faces.box.height ,\', "width":\' , faces.box.width , \'}}\' ) ,\']\') as media_metadataFaces' : '\'[\' || GROUP_CONCAT( \'{"name": "\' || person.name || \'", "box": {"top":\' || faces.box.top || \', "left":\' || faces.box.left || \', "height":\' || faces.box.height ||\', "width":\' || faces.box.width || \'}}\' ) ||\']\' as media_metadataFaces'; private DIRECTORY_SELECT = ['directory.id', 'directory.name', 'directory.path']; + // makes all search query params unique, so typeorm wont mix them + private queryIdBase = 0; private static autoCompleteItemsUnique(array: Array): Array { const a = array.concat(); @@ -247,7 +249,6 @@ export class SearchManager implements ISQLSearchManager { } - public async getCount(query: SearchQueryDTO): Promise { const connection = await SQLConnection.getConnection(); @@ -660,11 +661,21 @@ export class SearchManager implements ISQLSearchManager { * Witch SOME_OF query the number of WHERE constrains have O(N!) complexity */ private assignQueryIDs(queryIN: SearchQueryDTO, id = {value: 1}): SearchQueryDTO { + + // It is possible that one SQL query contains multiple searchQueries + // (like: where ( AND ()) + // lets make params unique across multiple queries + if (id.value === 1) { + this.queryIdBase++; + if (this.queryIdBase > 10000) { + this.queryIdBase = 0; + } + } if ((queryIN as SearchListQuery).list) { (queryIN as SearchListQuery).list.forEach(q => this.assignQueryIDs(q, id)); return queryIN; } - (queryIN as SearchQueryDTOWithID).queryId = id.value; + (queryIN as SearchQueryDTOWithID).queryId = this.queryIdBase + '_' + id.value; id.value++; return queryIN; } @@ -732,5 +743,5 @@ export class SearchManager implements ISQLSearchManager { } export interface SearchQueryDTOWithID extends SearchQueryDTO { - queryId: number; + queryId: string; } diff --git a/test/backend/unit/model/sql/PreviewManager.spec.ts b/test/backend/unit/model/sql/PreviewManager.spec.ts index b2a65e3e..c86ae1e8 100644 --- a/test/backend/unit/model/sql/PreviewManager.spec.ts +++ b/test/backend/unit/model/sql/PreviewManager.spec.ts @@ -231,6 +231,14 @@ describe('PreviewManager', (sqlHelper: DBTestHelper) => { text: 'Derem' } as TextSearch }))).to.deep.equalInAnyOrder(previewifyMedia(p2)); + // having a saved search that does not have any image + Config.Server.Preview.SearchQuery = {type: SearchQueryTypes.any_text, text: 'Derem'} as TextSearch; + expect(Utils.clone(await pm.getAlbumPreview({ + searchQuery: { + type: SearchQueryTypes.any_text, + text: 'wont find it' + } as TextSearch + }))).to.deep.equal(null); }); it('should invalidate and update preview', async () => {