blob: 88366fb0ca092d4dd0034bab51ce0ab10607955d [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015, 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { addErrorDescription } from "@core/core.functions";
import { MDMItem } from "@core/mdm-item";
import { PropertyService } from "@core/property.service";
import { Observable, of as observableOf } from "rxjs";
import { catchError, map } from "rxjs/operators";
export class Filter {
sourceName: string;
filter: string;
searchString: string;
constructor(sourceName: string, filter: string, searchString: string) {
this.sourceName = sourceName;
this.filter = filter;
this.searchString = searchString;
}
}
export class Query {
resultType: string;
filters: Filter[] = [];
columns: string[] = [];
resultOffset: number;
resultLimit: number;
addFilter(sourceName: string, filter: string) {
const f = this.filters.find((i) => i.sourceName === sourceName);
if (f) {
f.filter += " or " + filter; // TODO
} else {
this.filters.push(new Filter(sourceName, filter, ""));
}
}
}
export class Columns {
type: string;
attribute: string;
valueType: string;
value: any;
orderedValue: string;
}
export class Row {
source: string;
type: string;
id: string;
columns: Columns[] = [];
public static getColumn(row: Row, col: string) {
const column = row.columns.find((c) => c.type + "." + c.attribute === col);
if (column) {
return column.value;
} else {
return "";
}
}
public static equals(a: Row, b: Row) {
return a.source === b.source && a.type === b.type && a.id === b.id;
}
public static getItem(row: Row) {
return new MDMItem(row.source, row.type, row.id);
}
/**
* A complete id is needed as cross-source and cross-type items can be used in the basket
*/
public getVirtualId() {
return this.source + "_" + this.type + "_" + this.id;
}
}
export class SearchResult {
rows: Row[] = [];
totalRecords: { [source: string]: number };
}
@Injectable()
export class QueryService {
private queryUrl: string;
constructor(private http: HttpClient, private _prop: PropertyService) {
this.queryUrl = _prop.getUrl("mdm/query");
}
query(query: Query): Observable<SearchResult> {
return this.http.post<any>(this.queryUrl, query).pipe(
map((res) => <SearchResult>res),
catchError((e) => addErrorDescription(e, "Could not request search result!")),
);
}
/**
* Invoked from mdm basket component only when itemsAdded is emitted on basket service
* @param items
* @param columns
* @param caseSensitive
* @param patchFilter true if the filter should be patched for case sensitivity
*/
queryItems(items: MDMItem[], columns: string[], caseSensitive = false, patchFilter = false): Observable<SearchResult>[] {
const byType = items.reduce((acc: { [byType: string]: MDMItem[] }, item: MDMItem) => {
const key = item.type;
acc[key] = acc[key] || [];
acc[key].push(item);
return acc;
}, {});
return Object.keys(byType).map((type) => this.queryType(type, byType[type], columns, caseSensitive, patchFilter));
}
queryType(type: string, items: MDMItem[], columns: string[], caseSensitive = false, patchFilter = false) {
if (items && items.length > 0) {
const query = new Query();
query.resultType = type;
query.columns = columns;
// the id of the type
query.columns.push(type + ".Id");
const equalStr = caseSensitive ? "eq" : "ci_eq";
// add filter for the item
items.forEach((i) => {
if (i.id === undefined) {
// use the original filter from the virtual node and query all elements of the provided type
query.addFilter(i.source, this.patchFilterForCase(i.filter, caseSensitive, patchFilter));
} else {
// non-virtual node, query exact the requested item
query.addFilter(i.source, i.type + ".Id " + equalStr + ' "' + i.id + '"');
}
});
return this.query(query);
} else {
return observableOf(new SearchResult());
}
}
patchFilterForCase(filter: any, caseSensitive: boolean, patchFilter: boolean) {
let patched = filter;
// filters are case sensitive by default from the nodeprovider implementation
// also remove measured and ordered context
if (!caseSensitive && patchFilter) {
patched = patched.replace(/\seq\s/g, " ci_eq ");
patched = patched.replace(/MEASURED\./g, "");
patched = patched.replace(/ORDERED\./g, "");
}
return patched;
}
suggestValues(environments: string[], type: string, attribute: string) {
const body = JSON.stringify({
sourceNames: environments,
type: type,
attrName: attribute,
});
const headers = new HttpHeaders({ "Content-Type": "application/json" });
const options = { headers: headers };
const url = this._prop.getUrl("mdm/suggestions");
return this.http.post<any>(url, body, options).pipe(
map((res) => res.data),
catchError((e) => addErrorDescription(e, "Could not request suggestions!")),
);
}
}