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