2018-03-31 03:30:30 +08:00
|
|
|
import {AutoCompleteItem, SearchTypes} from '../../../common/entities/AutoCompleteItem';
|
|
|
|
import {ISearchManager} from '../interfaces/ISearchManager';
|
|
|
|
import {SearchResultDTO} from '../../../common/entities/SearchResultDTO';
|
|
|
|
import {SQLConnection} from './SQLConnection';
|
|
|
|
import {PhotoEntity} from './enitites/PhotoEntity';
|
|
|
|
import {DirectoryEntity} from './enitites/DirectoryEntity';
|
2018-11-18 05:46:34 +08:00
|
|
|
import {MediaEntity} from './enitites/MediaEntity';
|
2018-11-24 21:21:46 +08:00
|
|
|
import {VideoEntity} from './enitites/VideoEntity';
|
2016-12-28 18:50:05 +08:00
|
|
|
|
|
|
|
export class SearchManager implements ISearchManager {
|
|
|
|
|
2018-01-31 09:01:16 +08:00
|
|
|
private static autoCompleteItemsUnique(array: Array<AutoCompleteItem>): Array<AutoCompleteItem> {
|
2018-05-13 00:19:51 +08:00
|
|
|
const a = array.concat();
|
2018-01-31 09:01:16 +08:00
|
|
|
for (let i = 0; i < a.length; ++i) {
|
|
|
|
for (let j = i + 1; j < a.length; ++j) {
|
2018-05-13 00:19:51 +08:00
|
|
|
if (a[i].equals(a[j])) {
|
2018-01-31 09:01:16 +08:00
|
|
|
a.splice(j--, 1);
|
2018-05-13 00:19:51 +08:00
|
|
|
}
|
2018-01-31 09:01:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
async autocomplete(text: string): Promise<Array<AutoCompleteItem>> {
|
2017-07-08 06:18:24 +08:00
|
|
|
|
2017-07-21 05:37:10 +08:00
|
|
|
const connection = await SQLConnection.getConnection();
|
2017-07-08 06:18:24 +08:00
|
|
|
|
2018-11-18 05:46:34 +08:00
|
|
|
let result: AutoCompleteItem[] = [];
|
2018-05-13 00:19:51 +08:00
|
|
|
const photoRepository = connection.getRepository(PhotoEntity);
|
2018-11-24 21:21:46 +08:00
|
|
|
const videoRepository = connection.getRepository(VideoEntity);
|
2018-11-18 05:46:34 +08:00
|
|
|
const mediaRepository = connection.getRepository(MediaEntity);
|
2018-05-13 00:19:51 +08:00
|
|
|
const directoryRepository = connection.getRepository(DirectoryEntity);
|
2017-07-08 06:18:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
(await photoRepository
|
2018-11-18 05:46:34 +08:00
|
|
|
.createQueryBuilder('photo')
|
|
|
|
.select('DISTINCT(photo.metadata.keywords)')
|
|
|
|
.where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(5)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getRawMany())
|
2018-11-18 05:46:34 +08:00
|
|
|
.map(r => <Array<string>>(<string>r.metadataKeywords).split(','))
|
2017-07-08 06:18:24 +08:00
|
|
|
.forEach(keywords => {
|
2018-05-13 00:19:51 +08:00
|
|
|
result = result.concat(this.encapsulateAutoComplete(keywords
|
|
|
|
.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) !== -1), SearchTypes.keyword));
|
2017-07-08 06:18:24 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
(await photoRepository
|
2018-11-18 05:46:34 +08:00
|
|
|
.createQueryBuilder('photo')
|
|
|
|
.select('photo.metadata.positionData.country as country, ' +
|
|
|
|
'photo.metadata.positionData.state as state, photo.metadata.positionData.city as city')
|
|
|
|
.where('photo.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('photo.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.groupBy('photo.metadata.positionData.country, photo.metadata.positionData.state, photo.metadata.positionData.city')
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(5)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getRawMany())
|
|
|
|
.filter(pm => !!pm)
|
2018-03-31 03:30:30 +08:00
|
|
|
.map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || ''])
|
2017-07-08 06:18:24 +08:00
|
|
|
.forEach(positions => {
|
2018-05-13 00:19:51 +08:00
|
|
|
result = result.concat(this.encapsulateAutoComplete(positions
|
|
|
|
.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) !== -1), SearchTypes.position));
|
2017-07-08 06:18:24 +08:00
|
|
|
});
|
|
|
|
|
2018-11-24 21:21:46 +08:00
|
|
|
result = result.concat(this.encapsulateAutoComplete((await photoRepository
|
2018-11-05 02:28:32 +08:00
|
|
|
.createQueryBuilder('media')
|
|
|
|
.select('DISTINCT(media.name)')
|
|
|
|
.where('media.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(5)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getRawMany())
|
2018-11-24 21:21:46 +08:00
|
|
|
.map(r => r.name), SearchTypes.photo));
|
|
|
|
|
|
|
|
result = result.concat(this.encapsulateAutoComplete((await videoRepository
|
|
|
|
.createQueryBuilder('media')
|
|
|
|
.select('DISTINCT(media.name)')
|
|
|
|
.where('media.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.limit(5)
|
|
|
|
.getRawMany())
|
|
|
|
.map(r => r.name), SearchTypes.video));
|
2017-07-08 06:18:24 +08:00
|
|
|
|
|
|
|
result = result.concat(this.encapsulateAutoComplete((await directoryRepository
|
|
|
|
.createQueryBuilder('dir')
|
|
|
|
.select('DISTINCT(dir.name)')
|
2018-03-31 03:30:30 +08:00
|
|
|
.where('dir.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(5)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getRawMany())
|
|
|
|
.map(r => r.name), SearchTypes.directory));
|
|
|
|
|
|
|
|
|
2018-01-31 09:01:16 +08:00
|
|
|
return SearchManager.autoCompleteItemsUnique(result);
|
2017-07-08 04:54:18 +08:00
|
|
|
}
|
|
|
|
|
2018-01-31 09:01:16 +08:00
|
|
|
async search(text: string, searchType: SearchTypes): Promise<SearchResultDTO> {
|
2017-07-21 05:37:10 +08:00
|
|
|
const connection = await SQLConnection.getConnection();
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2018-01-31 09:01:16 +08:00
|
|
|
const result: SearchResultDTO = <SearchResultDTO>{
|
2017-07-08 06:18:24 +08:00
|
|
|
searchText: text,
|
|
|
|
searchType: searchType,
|
|
|
|
directories: [],
|
2018-11-05 02:28:32 +08:00
|
|
|
media: [],
|
2017-07-26 03:36:28 +08:00
|
|
|
resultOverflow: false
|
2017-07-08 06:18:24 +08:00
|
|
|
};
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2018-11-24 21:21:46 +08:00
|
|
|
let repostiroy = connection.getRepository(MediaEntity);
|
|
|
|
|
|
|
|
if (searchType === SearchTypes.photo) {
|
|
|
|
repostiroy = connection.getRepository(PhotoEntity);
|
|
|
|
} else if (searchType === SearchTypes.video) {
|
|
|
|
repostiroy = connection.getRepository(VideoEntity);
|
|
|
|
}
|
|
|
|
|
|
|
|
const query = repostiroy.createQueryBuilder('media')
|
2018-11-05 02:28:32 +08:00
|
|
|
.innerJoinAndSelect('media.directory', 'directory')
|
|
|
|
.orderBy('media.metadata.creationDate', 'ASC');
|
2017-07-08 04:54:18 +08:00
|
|
|
|
|
|
|
|
2017-07-08 06:18:24 +08:00
|
|
|
if (!searchType || searchType === SearchTypes.directory) {
|
2018-03-31 03:30:30 +08:00
|
|
|
query.orWhere('directory.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'});
|
2017-07-08 06:18:24 +08:00
|
|
|
}
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2018-11-24 21:21:46 +08:00
|
|
|
if (!searchType || searchType === SearchTypes.photo || searchType === SearchTypes.video) {
|
2018-11-05 02:28:32 +08:00
|
|
|
query.orWhere('media.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'});
|
2017-07-08 06:18:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!searchType || searchType === SearchTypes.position) {
|
2018-11-05 02:28:32 +08:00
|
|
|
query.orWhere('media.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('media.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('media.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'});
|
2018-01-31 09:01:16 +08:00
|
|
|
|
2017-07-08 06:18:24 +08:00
|
|
|
}
|
|
|
|
if (!searchType || searchType === SearchTypes.keyword) {
|
2018-11-05 02:28:32 +08:00
|
|
|
query.orWhere('media.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'});
|
2017-07-08 06:18:24 +08:00
|
|
|
}
|
2018-01-31 09:01:16 +08:00
|
|
|
|
2018-11-05 02:28:32 +08:00
|
|
|
result.media = await query
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(2001)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getMany();
|
|
|
|
|
2018-11-05 02:28:32 +08:00
|
|
|
if (result.media.length > 2000) {
|
2018-01-31 09:01:16 +08:00
|
|
|
result.resultOverflow = true;
|
2017-07-08 06:18:24 +08:00
|
|
|
}
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2017-07-08 06:18:24 +08:00
|
|
|
result.directories = await connection
|
|
|
|
.getRepository(DirectoryEntity)
|
2018-03-31 03:30:30 +08:00
|
|
|
.createQueryBuilder('dir')
|
|
|
|
.where('dir.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(201)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getMany();
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2017-07-26 03:36:28 +08:00
|
|
|
if (result.directories.length > 200) {
|
|
|
|
result.resultOverflow = true;
|
|
|
|
}
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2017-07-08 06:18:24 +08:00
|
|
|
return result;
|
2017-07-08 04:54:18 +08:00
|
|
|
}
|
|
|
|
|
2018-01-31 09:01:16 +08:00
|
|
|
async instantSearch(text: string): Promise<SearchResultDTO> {
|
2017-07-21 05:37:10 +08:00
|
|
|
const connection = await SQLConnection.getConnection();
|
2017-07-08 06:18:24 +08:00
|
|
|
|
2018-05-13 00:19:51 +08:00
|
|
|
const result: SearchResultDTO = <SearchResultDTO>{
|
2017-07-08 06:18:24 +08:00
|
|
|
searchText: text,
|
2018-05-13 00:19:51 +08:00
|
|
|
// searchType:undefined, not adding this
|
2017-07-08 06:18:24 +08:00
|
|
|
directories: [],
|
2018-11-05 02:28:32 +08:00
|
|
|
media: [],
|
2017-07-26 03:36:28 +08:00
|
|
|
resultOverflow: false
|
2017-07-08 06:18:24 +08:00
|
|
|
};
|
|
|
|
|
2018-11-05 02:28:32 +08:00
|
|
|
result.media = await connection
|
2018-11-24 18:50:22 +08:00
|
|
|
.getRepository(MediaEntity)
|
2018-11-05 02:28:32 +08:00
|
|
|
.createQueryBuilder('media')
|
|
|
|
.orderBy('media.metadata.creationDate', 'ASC')
|
|
|
|
.where('media.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('media.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('media.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('media.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.orWhere('media.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
|
|
|
.innerJoinAndSelect('media.directory', 'directory')
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(10)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getMany();
|
|
|
|
|
|
|
|
|
2018-01-31 09:01:16 +08:00
|
|
|
result.directories = await connection
|
2017-07-08 06:18:24 +08:00
|
|
|
.getRepository(DirectoryEntity)
|
2018-03-31 03:30:30 +08:00
|
|
|
.createQueryBuilder('dir')
|
|
|
|
.where('dir.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
2017-10-20 00:08:07 +08:00
|
|
|
.limit(10)
|
2017-07-08 06:18:24 +08:00
|
|
|
.getMany();
|
2017-07-08 04:54:18 +08:00
|
|
|
|
2017-07-08 06:18:24 +08:00
|
|
|
return result;
|
2017-07-08 04:54:18 +08:00
|
|
|
}
|
|
|
|
|
2018-11-24 21:21:46 +08:00
|
|
|
private encapsulateAutoComplete(values: string[], type: SearchTypes): Array<AutoCompleteItem> {
|
2018-05-13 00:19:51 +08:00
|
|
|
const res = [];
|
2017-07-08 04:54:18 +08:00
|
|
|
values.forEach((value) => {
|
|
|
|
res.push(new AutoCompleteItem(value, type));
|
|
|
|
});
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|