1
0
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:
Braun Patrik 2016-12-28 11:50:05 +01:00
parent 53ab3d34a9
commit 3ad2f6612f
11 changed files with 127 additions and 40 deletions

View File

@ -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));
}

View File

@ -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());

View File

@ -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;
}

View File

@ -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");
}

View 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;
}
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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>;
}

View File

@ -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",

View File

@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"sourceMap": true,
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"exclude": [
"node_modules",
"typings"
]
}

View File

@ -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"
]
}