mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-11-28 08:58:49 +02:00
implementing mysql autocomplete
This commit is contained in:
parent
53ab3d34a9
commit
3ad2f6612f
@ -6,7 +6,7 @@ import {DirectoryDTO} from "../../common/entities/DirectoryDTO";
|
||||
import {ObjectManagerRepository} from "../model/ObjectManagerRepository";
|
||||
import {AutoCompleteItem, SearchTypes} from "../../common/entities/AutoCompleteItem";
|
||||
import {ContentWrapper} from "../../common/entities/ConentWrapper";
|
||||
import {SearchResult} from "../../common/entities/SearchResult";
|
||||
import {SearchResultDTO} from "../../common/entities/SearchResult";
|
||||
import {PhotoDTO} from "../../common/entities/PhotoDTO";
|
||||
import {Config} from "../config/Config";
|
||||
import {ProjectPath} from "../ProjectPath";
|
||||
@ -87,7 +87,7 @@ export class GalleryMWs {
|
||||
type = parseInt(req.query.type);
|
||||
}
|
||||
|
||||
ObjectManagerRepository.getInstance().getSearchManager().search(req.params.text, type, (err, result:SearchResult) => {
|
||||
ObjectManagerRepository.getInstance().getSearchManager().search(req.params.text, type, (err, result: SearchResultDTO) => {
|
||||
if (err || !result) {
|
||||
return next(new Error(ErrorCodes.GENERAL_ERROR, err));
|
||||
}
|
||||
@ -107,7 +107,7 @@ export class GalleryMWs {
|
||||
}
|
||||
|
||||
|
||||
ObjectManagerRepository.getInstance().getSearchManager().instantSearch(req.params.text, (err, result:SearchResult) => {
|
||||
ObjectManagerRepository.getInstance().getSearchManager().instantSearch(req.params.text, (err, result: SearchResultDTO) => {
|
||||
if (err || !result) {
|
||||
return next(new Error(ErrorCodes.GENERAL_ERROR, err));
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export class ObjectManagerRepository {
|
||||
MySQLConnection.init().then(() => {
|
||||
const GalleryManager = require("./mysql/GalleryManager").GalleryManager;
|
||||
const UserManager = require("./mysql/UserManager").UserManager;
|
||||
const SearchManager = require("./memory/SearchManager").SearchManager;
|
||||
const SearchManager = require("./mysql/SearchManager").SearchManager;
|
||||
ObjectManagerRepository.getInstance().setGalleryManager(new GalleryManager());
|
||||
ObjectManagerRepository.getInstance().setUserManager(new UserManager());
|
||||
ObjectManagerRepository.getInstance().setSearchManager(new SearchManager());
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {AutoCompleteItem, SearchTypes} from "../../../common/entities/AutoCompleteItem";
|
||||
import {SearchResult} from "../../../common/entities/SearchResult";
|
||||
import {SearchResultDTO} from "../../../common/entities/SearchResult";
|
||||
export interface ISearchManager {
|
||||
autocomplete(text: string, cb: (error: any, result: Array<AutoCompleteItem>) => void): void;
|
||||
search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResult) => void): void;
|
||||
instantSearch(text: string, cb: (error: any, result: SearchResult) => void): void;
|
||||
search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void): void;
|
||||
instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void): void;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import {AutoCompleteItem, SearchTypes} from "../../../common/entities/AutoCompleteItem";
|
||||
import {ISearchManager} from "../interfaces/ISearchManager";
|
||||
import {SearchResult} from "../../../common/entities/SearchResult";
|
||||
import {SearchResultDTO} from "../../../common/entities/SearchResult";
|
||||
|
||||
export class SearchManager implements ISearchManager {
|
||||
|
||||
@ -9,11 +9,11 @@ export class SearchManager implements ISearchManager {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResult) => void) {
|
||||
search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void) {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
instantSearch(text: string, cb: (error: any, result: SearchResult) => void) {
|
||||
instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void) {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
|
101
backend/model/mysql/SearchManager.ts
Normal file
101
backend/model/mysql/SearchManager.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import {AutoCompleteItem, SearchTypes} from "../../../common/entities/AutoCompleteItem";
|
||||
import {ISearchManager} from "../interfaces/ISearchManager";
|
||||
import {SearchResultDTO} from "../../../common/entities/SearchResult";
|
||||
import {MySQLConnection} from "./MySQLConnection";
|
||||
import {PhotoEntity} from "./enitites/PhotoEntity";
|
||||
import {DirectoryEnitity} from "./enitites/DirectoryEntity";
|
||||
import {PositionMetaData} from "../../../common/entities/PhotoDTO";
|
||||
|
||||
export class SearchManager implements ISearchManager {
|
||||
|
||||
|
||||
autocomplete(text: string, cb: (error: any, result: Array<AutoCompleteItem>) => void) {
|
||||
|
||||
MySQLConnection.getConnection().then(async connection => {
|
||||
try {
|
||||
let result: Array<AutoCompleteItem> = [];
|
||||
let photoRepository = connection.getRepository(PhotoEntity);
|
||||
let directoryRepository = connection.getRepository(DirectoryEnitity);
|
||||
|
||||
|
||||
(await photoRepository
|
||||
.createQueryBuilder('photo')
|
||||
.select('DISTINCT(photo.metadataKeywords)')
|
||||
.where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"})
|
||||
.setLimit(5)
|
||||
.getRawMany<{metadataKeywords: string}>())
|
||||
.map(r => <Array<string>>JSON.parse(r.metadataKeywords))
|
||||
.forEach(keywords => {
|
||||
result = result.concat(this.encapsulateAutoComplete(keywords.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.keyword));
|
||||
});
|
||||
|
||||
|
||||
(await photoRepository
|
||||
.createQueryBuilder('photo')
|
||||
.select('DISTINCT(photo.metadataPositionData)')
|
||||
.where('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"})
|
||||
.setLimit(5)
|
||||
.getRawMany<{metadataPositionData: string}>())
|
||||
.map(r => <PositionMetaData>JSON.parse(r.metadataPositionData))
|
||||
.map(pm => <Array<string>>[pm.city || "", pm.country || "", pm.state || ""])
|
||||
.forEach(positions => {
|
||||
result = result.concat(this.encapsulateAutoComplete(positions.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.position));
|
||||
});
|
||||
|
||||
|
||||
result = result.concat(this.encapsulateAutoComplete((await photoRepository
|
||||
.createQueryBuilder('photo')
|
||||
.select('DISTINCT(photo.name)')
|
||||
.where('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"})
|
||||
.setLimit(5)
|
||||
.getRawMany<{name: string}>())
|
||||
.map(r => r.name), SearchTypes.image));
|
||||
|
||||
result = result.concat(this.encapsulateAutoComplete((await directoryRepository
|
||||
.createQueryBuilder('dir')
|
||||
.select('DISTINCT(dir.name)')
|
||||
.where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"})
|
||||
.setLimit(5)
|
||||
.getRawMany<{name: string}>())
|
||||
.map(r => r.name), SearchTypes.directory));
|
||||
|
||||
|
||||
return cb(null, this.autoCompleteItemsUnique(result));
|
||||
} catch (error) {
|
||||
return cb(error, null);
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
return cb(error, null);
|
||||
});
|
||||
}
|
||||
|
||||
search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void) {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void) {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
private encapsulateAutoComplete(values: Array<string>, type: SearchTypes) {
|
||||
let res = [];
|
||||
values.forEach((value) => {
|
||||
res.push(new AutoCompleteItem(value, type));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private autoCompleteItemsUnique(array: Array<AutoCompleteItem>) {
|
||||
let a = array.concat();
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
for (let j = i + 1; j < a.length; ++j) {
|
||||
if (a[i].equals(a[j]))
|
||||
a.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
@ -42,9 +42,9 @@ export class ConfigClass {
|
||||
public Client:ClientConfig = {
|
||||
thumbnailSizes: [200, 400, 600],
|
||||
Search: {
|
||||
searchEnabled: false,
|
||||
instantSearchEnabled: false,
|
||||
autocompleteEnabled: false
|
||||
searchEnabled: true,
|
||||
instantSearchEnabled: true,
|
||||
autocompleteEnabled: true
|
||||
},
|
||||
concurrentThumbnailGenerations: 1,
|
||||
enableCache: false,
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {SearchResult} from "./SearchResult";
|
||||
import {SearchResultDTO} from "./SearchResult";
|
||||
export class ContentWrapper {
|
||||
|
||||
public directory: DirectoryDTO;
|
||||
public searchResult:SearchResult;
|
||||
public searchResult: SearchResultDTO;
|
||||
|
||||
constructor(directory: DirectoryDTO = null, searchResult: SearchResult = null) {
|
||||
constructor(directory: DirectoryDTO = null, searchResult: SearchResultDTO = null) {
|
||||
this.directory = directory;
|
||||
this.searchResult = searchResult;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {PhotoDTO} from "./PhotoDTO";
|
||||
import {SearchTypes} from "./AutoCompleteItem";
|
||||
export class SearchResult {
|
||||
public searchText:string = "";
|
||||
public searchType:SearchTypes;
|
||||
public directories: Array<DirectoryDTO> = [];
|
||||
public photos: Array<PhotoDTO> = [];
|
||||
export interface SearchResultDTO {
|
||||
searchText: string;
|
||||
searchType: SearchTypes;
|
||||
directories: Array<DirectoryDTO>;
|
||||
photos: Array<PhotoDTO>;
|
||||
}
|
@ -8,8 +8,8 @@
|
||||
"license": "MIT",
|
||||
"main": "./backend/server.js",
|
||||
"scripts": {
|
||||
"postinstall": "tsc -p frontend && tsc -p backend && tsc -p test/backend && tsc -p common",
|
||||
"pretest": "tsc -p frontend && tsc -p backend && tsc -p test/backend",
|
||||
"postinstall": "tsc",
|
||||
"pretest": "tsc",
|
||||
"test": "karma start karma.conf.js --single-run && mocha --recursive test/backend/unit",
|
||||
"start": "node ./backend/server"
|
||||
},
|
||||
@ -53,7 +53,6 @@
|
||||
"zone.js": "^0.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/core-js": "^0.9.35",
|
||||
"@types/express": "^4.0.34",
|
||||
"@types/express-session": "0.0.32",
|
||||
"@types/jasmine": "^2.5.38",
|
||||
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"sourceMap": true,
|
||||
"module": "commonjs",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"typings"
|
||||
]
|
||||
}
|
@ -8,7 +8,8 @@
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"es2015",
|
||||
"dom"
|
||||
"dom",
|
||||
"es2015.promise"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": false,
|
||||
"typeRoots": [
|
||||
@ -16,7 +17,6 @@
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"node_modules/@types"
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user