Mercurial > hg > ng2-query-ismi
changeset 20:34cd764e234b
make interfaces into classes. factor out NormalizationService.
author | casties |
---|---|
date | Fri, 22 Jan 2016 17:32:33 +0100 |
parents | d75224bb8147 |
children | 930fe7460f6b |
files | app/query-app.component.ts app/query-select.component.ts app/query-state.ts app/query-step.ts app/query.service.ts |
diffstat | 5 files changed, 105 insertions(+), 84 deletions(-) [+] |
line wrap: on
line diff
--- a/app/query-app.component.ts Thu Jan 21 20:22:02 2016 +0100 +++ b/app/query-app.component.ts Fri Jan 22 17:32:33 2016 +0100 @@ -1,19 +1,22 @@ import {Component} from 'angular2/core'; import {HTTP_PROVIDERS} from 'angular2/http'; -import {QueryService} from './query.service'; import {QueryState} from './query-state'; import {QueryStep} from './query-step'; +import {QueryService} from './query.service'; +import {NormalizationService} from './normalization.service'; + import {QuerySelectComponent} from './query-select.component'; import {QueryResultComponent} from './query-result.component'; +//import {QueryResultTableComponent} from './query-result-table.component'; @Component({ selector: 'query-app', template: ` <h1>ISMI-Lab Query Builder</h1> <div>Select a query step:</div> - <query-select *ngFor="#step of querySteps; #i=index;" + <query-select *ngFor="#step of queryStepList; #i=index;" [queryStep]="step" [index]="i" (queryChanged)="onQueryChanged($event)"></query-select> <div> @@ -23,25 +26,25 @@ <query-result [queryState]="queryState"></query-result> `, directives: [QuerySelectComponent, QueryResultComponent], - providers: [QueryService, HTTP_PROVIDERS] + providers: [QueryService, NormalizationService, HTTP_PROVIDERS] }) export class QueryAppComponent { public queryState: QueryState; - public querySteps: QueryStep[]; + public queryStepList: string[]; constructor(private _queryService: QueryService) { this._queryService.setup(); - this.querySteps = []; + this.queryStepList = []; this.addQueryStep(); } addQueryStep() { - this.querySteps.push({'mode': null}); + this.queryStepList.push('step'); } removeQueryStep() { - this.querySteps.pop(); + this.queryStepList.pop(); this._queryService.state.steps.pop(); }
--- a/app/query-select.component.ts Thu Jan 21 20:22:02 2016 +0100 +++ b/app/query-select.component.ts Fri Jan 22 17:32:33 2016 +0100 @@ -1,10 +1,12 @@ import {Component, Output, EventEmitter, OnInit} from 'angular2/core'; -import {QueryService} from './query.service'; import {QueryMode} from './query-mode'; import {QueryStep} from './query-step'; import {QueryState} from './query-state'; +import {QueryService} from './query.service'; +import {NormalizationService} from './normalization.service'; + @Component({ selector: 'query-select', @@ -19,7 +21,7 @@ </option> </select> - <span *ngIf="selectedMode && selectedMode.id=='type_is' || selectedMode.id=='relation_is'"> + <span *ngIf="selectedMode && (selectedMode.id=='type_is' || selectedMode.id=='relation_is')"> <select *ngIf="queryOptions" [(ngModel)]="selectedOption" (change)="onSelectOption($event)"> <option></option> <option *ngFor="#option of queryOptions" [value]="option"> @@ -28,7 +30,7 @@ </select> </span> - <span *ngIf="selectedMode && selectedMode.id=='att_contains' || selectedMode.id=='att_contains_norm'"> + <span *ngIf="selectedMode && (selectedMode.id=='att_contains' || selectedMode.id=='att_contains_norm')"> <select [(ngModel)]="selectedOption"> <option></option> <option *ngFor="#option of queryOptions" [value]="option"> @@ -61,7 +63,7 @@ }) export class QuerySelectComponent implements OnInit { - public queryStep: QueryStep; + public queryStep: string; public index: number; public resultInfo: string; public queryModes: QueryMode[]; @@ -73,7 +75,7 @@ @Output('queryChanged') queryChanged = new EventEmitter<QueryState>(); - constructor(private _queryService: QueryService) {} + constructor(private _queryService: QueryService, private _normService: NormalizationService) {} ngOnInit() { this.setup(); @@ -86,9 +88,6 @@ if (step != null) { this.resultInfo = step.resultInfo; } - // select first mode (too early?) - this.selectedMode = this.queryModes[0]; - this.query2Options = this._queryService.getQueryOptions(this.selectedMode); } onSelectMode(event: any) { @@ -110,36 +109,36 @@ if (this.selectedMode.id == 'type_is') { var opt = this.selectedOption; if (opt) { - step = {'mode': this.selectedMode, 'objectType': opt}; + step = new QueryStep(this.selectedMode, {'objectType': opt}); } } else if (this.selectedMode.id == 'relation_is') { var opt = this.selectedOption; if (opt) { - step = {'mode': this.selectedMode, 'relationType': opt}; + step = new QueryStep(this.selectedMode, {'relationType': opt}); } } else if (this.selectedMode.id == 'att_contains') { var att = this.selectedOption; var val = this.queryInput; if (att && val) { - step = {'mode': this.selectedMode, 'attribute': att, 'value': val}; + step = new QueryStep(this.selectedMode, {'attribute': att, 'value': val}); } } else if (this.selectedMode.id == 'att_num_range') { var att = this.selectedOption; var nlo = this.queryInput; var nhi = this.queryInput2; if (att && nlo && nhi) { - step = {'mode': this.selectedMode, 'attribute': att, 'numLo': nlo, 'numHi': nhi}; + step = new QueryStep(this.selectedMode, {'attribute': att, 'numLo': nlo, 'numHi': nhi}); } } else if (this.selectedMode.id == 'att_contains_norm') { var att = this.selectedOption; var val = this.queryInput; if (att && val) { // run search term through normalizer - this._queryService.fetchNormalizedString(val) + this._normService.fetchArabicTranslitNormalizedString(val) .subscribe( data => { console.debug("openmind norm data=", data); - step = {'mode': this.selectedMode, 'attribute': att, 'value': val, 'normValue': data.normalized_text}; + step = new QueryStep(this.selectedMode, {'attribute': att, 'value': val, 'normValue': data.normalized_text}); this._queryService.setQueryStep(this.index, step); // query has changed now this.queryChanged.emit(this._queryService.getState());
--- a/app/query-state.ts Thu Jan 21 20:22:02 2016 +0100 +++ b/app/query-state.ts Fri Jan 22 17:32:33 2016 +0100 @@ -1,10 +1,19 @@ import {QueryStep} from './query-step'; -export interface QueryState { - steps: QueryStep[]; - cypherQuery: string; - cypherParams: any; - resultTypes: string; - results: any[]; - numResults: number; +export class QueryState { + public steps: QueryStep[] = []; + + public resultCypherQuery: string; + public attributesCypherQuery: string; + public relationsCypherQuery: string; + public cypherQueryParams: any; + + public results: any[]; + public numResults: number; + public resultTypes: string; + public resultInfo: string; + + public nextQueryRelations: any[]; + public nextQueryAttributes: any[]; + } \ No newline at end of file
--- a/app/query-step.ts Thu Jan 21 20:22:02 2016 +0100 +++ b/app/query-step.ts Fri Jan 22 17:32:33 2016 +0100 @@ -1,6 +1,14 @@ import {QueryMode} from './query-mode'; -export interface QueryStep { - mode: QueryMode; - objectType?: string; +export class QueryStep { + public mode: QueryMode; + + public params: any; + + public resultInfo: string; + + constructor (mode: QueryMode, params: any) { + this.mode = mode; + this.params = params; + } } \ No newline at end of file
--- a/app/query.service.ts Thu Jan 21 20:22:02 2016 +0100 +++ b/app/query.service.ts Fri Jan 22 17:32:33 2016 +0100 @@ -12,29 +12,19 @@ //public neo4jBaseUrl = 'https://ismi-dev.mpiwg-berlin.mpg.de/neo4j-ismi/db/data'; public neo4jBaseUrl = 'http://localhost:7474/db/data'; - public openMindBaseUrl = 'https://ismi-dev.mpiwg-berlin.mpg.de/om4-ismi/'; - //public openMindBaseUrl = 'http://localhost:18080/ismi-richfaces/'; + public neo4jAuthentication = {'user': 'neo4j', 'password': 'neo5j'}; public excludedAttributes = {'type': true}; public invRelPrefix = '<- '; public state: QueryState; - public ismiObjectTypes: any; + public objectTypes: string[]; constructor(private _http: Http) { - this.state = { - 'steps': [], - 'resultCypherQuery': '', - 'cypherQueryParams': {}, - 'attributesCypherQuery': '', - 'relationsCypherQuery': '', - 'results': [], - 'resultTypes': '', - 'numResults': 0, - 'resultInfo': '' - }; + // init query state + this.state = new QueryState(); } setup() { - this.setupIsmiObjectTypes(); + this.setupObjectTypes(); } getState() { @@ -45,11 +35,14 @@ return QUERY_MODES; } + /** + * return the first set of options for the given query mode. + */ getQueryOptions(queryMode: QueryMode) { var options = []; if (queryMode == null) return options; if (queryMode.id === 'type_is') { - options = this.ismiObjectTypes; + options = this.objectTypes; } else if (queryMode.id === 'relation_is') { options = this.state.nextQueryRelations; } else if (queryMode.id === 'att_contains') { @@ -63,7 +56,10 @@ return options; } - setupIsmiObjectTypes() { + /** + * fetch all object types from Neo4j and store in this.objectTypes. + */ + setupObjectTypes() { var query = `MATCH (n) WITH DISTINCT labels(n) AS labels UNWIND labels AS label RETURN DISTINCT label ORDER BY label`; @@ -72,19 +68,26 @@ res.subscribe( data => { console.debug("neo4j data=", data); - this.ismiObjectTypes = data.results[0].data.map(elem => elem.row[0]).filter(elem => elem[0] != "_"); - console.debug("ismi types=", this.ismiObjectTypes); + this.objectTypes = data.results[0].data.map(elem => elem.row[0]).filter(elem => elem[0] != "_"); + console.debug("object types=", this.objectTypes); }, err => console.error("neo4j error=", err), () => console.debug('neo4j query Complete') ); } + /** + * Set the query step at index. + */ setQueryStep(index: number, step: QueryStep) { this.state.steps[index] = step; - this.createCypherQuery(); } + /** + * Create the cypher queries for the current query state. + * + * Updates the queries for results, attributes and relations. + */ createCypherQuery() { var queryMatch = ''; var queryWhere = ''; @@ -96,11 +99,14 @@ var returnType = ''; var nIdx = 1; this.state.steps.forEach((step, stepIdx) => { + var mode = step.mode.id; + var params = step.params; + /* * step: object type is */ - if (step.mode.id === 'type_is') { - queryMatch = `MATCH (n${nIdx}:${step.objectType})`; + if (mode === 'type_is') { + queryMatch = `MATCH (n${nIdx}:${params.objectType})`; queryWhere = ''; queryReturn = `RETURN n${nIdx}`; returnType = 'node'; @@ -109,9 +115,9 @@ /* * step: relation type is */ - if (step.mode.id === 'relation_is') { + if (mode === 'relation_is') { nIdx += 1; - var rel = step.relationType; + var rel = params.relationType; if (rel.indexOf(this.invRelPrefix) == 0) { // inverse relation rel = rel.substr(this.invRelPrefix.length); @@ -126,24 +132,24 @@ /* * step: attribute contains(_norm) */ - if (step.mode.id === 'att_contains' || step.mode.id === 'att_contains_norm') { + if (mode === 'att_contains' || mode === 'att_contains_norm') { if (!queryWhere) { queryWhere = 'WHERE '; } else { queryWhere += ' AND '; } - if (step.attribute === 'ismi_id') { + if (params.attribute === 'ismi_id') { // ismi_id is integer queryWhere += `n${nIdx}.ismi_id = {att_val${stepIdx}}`; - queryParams[`att_val${stepIdx}`] = parseInt(step.value, 10); + queryParams[`att_val${stepIdx}`] = parseInt(params.value, 10); } else { - if (step.mode.id === 'att_contains_norm') { + if (mode === 'att_contains_norm') { // match _n_attribute with normValue - queryWhere += `lower(n${nIdx}._n_${step.attribute}) CONTAINS lower({att_val${stepIdx}})`; - queryParams[`att_val${stepIdx}`] = step.normValue; + queryWhere += `lower(n${nIdx}._n_${params.attribute}) CONTAINS lower({att_val${stepIdx}})`; + queryParams[`att_val${stepIdx}`] = params.normValue; } else { - queryWhere += `lower(n${nIdx}.${step.attribute}) CONTAINS lower({att_val${stepIdx}})`; - queryParams[`att_val${stepIdx}`] = step.value; + queryWhere += `lower(n${nIdx}.${params.attribute}) CONTAINS lower({att_val${stepIdx}})`; + queryParams[`att_val${stepIdx}`] = params.value; } } } @@ -151,16 +157,16 @@ /* * step: attribute number range */ - if (step.mode.id === 'att_num_range') { + if (mode === 'att_num_range') { if (!queryWhere) { queryWhere = 'WHERE '; } else { queryWhere += ' AND '; } - queryWhere += `toint(n${nIdx}.${step.attribute}) >= toint({att_nlo${stepIdx}})` - + ` AND toint(n${nIdx}.${step.attribute}) <= toint({att_nhi${stepIdx}})`; - queryParams[`att_nlo${stepIdx}`] = step.numLo; - queryParams[`att_nhi${stepIdx}`] = step.numHi; + queryWhere += `toint(n${nIdx}.${params.attribute}) >= toint({att_nlo${stepIdx}})` + + ` AND toint(n${nIdx}.${params.attribute}) <= toint({att_nhi${stepIdx}})`; + queryParams[`att_nlo${stepIdx}`] = params.numLo; + queryParams[`att_nhi${stepIdx}`] = params.numHi; } }); @@ -178,6 +184,11 @@ this.state.resultTypes = returnType; } + /** + * Create and run the cypher queries for the current query state. + * + * Updates the results and nextQuery attributes and relations. + */ updateQuery() { this.createCypherQuery(); this.state.resultInfo = 'loading...'; @@ -246,10 +257,16 @@ ); } + /** + * Run the given queries on the Neo4J server. + * + * Returns an Observable with the results. + */ fetchCypherResults(queries: string[], params=[{}]) { console.debug("fetching cypher queries: ", queries); var headers = new Headers(); - headers.append('Authorization', 'Basic ' + btoa('neo4j' + ':' + 'neo5j')); + var auth = this.neo4jAuthentication; + headers.append('Authorization', 'Basic ' + btoa(`${auth.user}:${auth.password}`)); headers.append('Content-Type', 'application/json'); headers.append('Accept', 'application/json'); // put headers in options @@ -268,19 +285,4 @@ return resp; } - fetchNormalizedString(text: string) { - console.debug("fetching normalized string: ", text); - var headers = new Headers(); - headers.append('Accept', 'application/json'); - // put headers in options - var opts = {'headers': headers}; - // make get request asynchronously - var url = this.openMindBaseUrl+'jsonInterface?method=normalize_string&type=arabic_translit&text='; - url += text; - var resp = this._http.get(url, opts) - // filter result as JSON - .map(res => res.json()); - // return Observable - return resp; - } } \ No newline at end of file