blob: 7a8852c4a779175c762011b020b1e04ddd2573cc [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 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 { plainToClass } from 'class-transformer';
import { map, catchError, shareReplay, tap, flatMap } from 'rxjs/operators';
import { HttpErrorHandler } from '../../core/http-error-handler';
import { PropertyService } from '../../core/property.service';
import { Node } from '../../navigator/node';
import { MeasuredValuesResponse, MeasuredValues, PreviewValueList, NumberArray, BooleanArray, DateArray, StringArray } from '../model/chartviewer.model';
import { QueryService, Query, Row } from '../../tableview/query.service';
import { Observable, of, Subject, throwError } from 'rxjs';
import { ChannelGroup } from '../model/types/channelgroup.class';
import { Channel } from '../model/types/channel.class';
import { Measurement } from '../model/types/measurement.class';
import { TYPE_CHANNEL, TYPE_CHANNELGROUP, TYPE_MEASUREMENT } from '../model/constants';
import { NavigatorService } from '@navigator/navigator.service';
import { QueryConfig } from '../model/types/query-config.class';
@Injectable({
providedIn: 'root'
})
export class ChartViewerDataService {
private _contextUrl: string;
public resultLimit: number = undefined;
public resultOffset = 0;
private httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
};
constructor(private http: HttpClient,
private httpErrorHandler: HttpErrorHandler,
private _prop: PropertyService,
private queryService: QueryService) {
this._contextUrl = _prop.getUrl('mdm/environments');
}
/**
* Loads preview value (if chunks > 0) or measured values (if chunks == 0).
* @param channelGroup channel group node
* @param channels channel nodes
* @param startIndex start index to load the data
* @param requestSize number of requested values
* @param chunks preview chunks. If 0, preview is disabled and original values are loaded
*/
loadValues(channelGroup: ChannelGroup, channels: Channel[], startIndex = 0, requestSize = 0, chunks = 0) {
if (chunks > 0) {
return this.loadPreviewValues(channelGroup, channels, chunks, startIndex, requestSize);
} else {
return this.loadMeasuredValues(channelGroup, channels, startIndex, requestSize);
}
}
/**
* Loads measured values
* @param channelGroup channel group node
* @param channels channel nodes
* @param startIndex start index to load the data
* @param requestSize number of requested values
*/
loadMeasuredValues(channelGroup: ChannelGroup, channels: Channel[], startIndex = 0, requestSize = 0) {
let readRequest = {
'channelGroupId': channelGroup.id,
'channelIds': channels !== undefined ? channels.filter(channel => channel.type === 'Channel').map(channel => channel.id) : [],
'start_index': startIndex,
'request_size': requestSize,
'valuesMode': 'CALCULATED'
};
return this.http.post<MeasuredValuesResponse>(this._contextUrl + '/' + channelGroup.source + '/values/read',
readRequest, this.httpOptions)
.pipe(
map(res => plainToClass(MeasuredValues, res.values)),
map(measurementValues => measurementValues.sort((a, b) => a.name.localeCompare(b.name))),
catchError(this.httpErrorHandler.handleError)
);
}
/**
* Loads preview values.
* @param channelGroup channel group node
* @param channels channel nodes
* @param chunks preview chunks
* @param startIndex start index to load the data
* @param requestSize number of requested values
*/
loadPreviewValues(channelGroup: ChannelGroup, channels: Channel[], chunks: number, startIndex = 0, requestSize = 0) {
let readRequest = {
'channelGroupId': channelGroup.id,
'channelIds': channels !== undefined ? channels.filter(channel => channel.type === 'Channel').map(channel => channel.id) : [],
'start_index': startIndex,
'request_size': requestSize,
'valuesMode': 'CALCULATED'
};
let previewRequest = {
'numberOfChunks': chunks,
'readRequest': readRequest
};
return this.http.post<PreviewValueList>(this._contextUrl + '/' + channelGroup.source + '/values/preview',
previewRequest, this.httpOptions)
.pipe(
map(res => plainToClass(MeasuredValues, res.avg)),
map(measurementValues => measurementValues.sort((a, b) => a.name.localeCompare(b.name))),
catchError(this.httpErrorHandler.handleError)
);
}
loadMeasurement(node: Node) {
if (node.type !== TYPE_MEASUREMENT && node.type !== TYPE_CHANNELGROUP && node.type !== TYPE_CHANNEL) {
return throwError('Node must be of type: ' + TYPE_MEASUREMENT + ' or ' + TYPE_CHANNELGROUP + ' or ' + TYPE_CHANNEL);
}
let measurementId: Observable<string[]>;
const source = node.sourceName ? node.sourceName : node.source;
if (node.type === TYPE_MEASUREMENT) {
measurementId = of([node.id, node.name ? node.name : node.label]);
} else {
// query id of the measurement
const queryMeasurementId = new Query();
queryMeasurementId.columns = [TYPE_MEASUREMENT + '.Id', TYPE_MEASUREMENT + '.Name'];
queryMeasurementId.resultType = TYPE_MEASUREMENT;
queryMeasurementId.resultLimit = 1;
queryMeasurementId.addFilter(source, node.type + '.Id eq ' + node.id);
measurementId = this.queryService.query(queryMeasurementId).pipe(
map(sr => [sr.rows.map(row => Row.getColumn(row, TYPE_MEASUREMENT + '.Id')),
sr.rows.map(row => Row.getColumn(row, TYPE_MEASUREMENT + '.Name'))]),
map(ids => ids.length > 0 ? ids as [] : undefined)
);
}
return measurementId.pipe(
flatMap(meaId => this.loadMeasurementById(source, meaId[0], meaId[1]))
);
}
loadMeasurementById(sourceName: string, measurementId: string, measurementName: string) {
const query = new Query();
query.addFilter(sourceName, 'Measurement.Id eq ' + measurementId);
query.columns = ['Measurement.Id', 'ChannelGroup.Id', 'ChannelGroup.Name', 'ChannelGroup.SubMatrixNoRows',
'Channel.Id', 'Channel.Name', 'LocalColumn.axistype', 'LocalColumn.IndependentFlag'];
query.resultType = 'LocalColumn';
query.resultOffset = this.resultOffset;
query.resultLimit = 0; // request all results
return this.queryService.query(query).pipe(
map(sr => sr.rows.map(row => this.mapRow(row))),
map(pairs => {
const mea = new Measurement();
mea.type = TYPE_MEASUREMENT;
mea.name = measurementName;
pairs.forEach(entry => {
mea.put(entry.channelGroup, entry.channel);
entry.channel.measurement = measurementName;
mea.source = entry.channelGroup.source;
mea.id = entry.meaId;
});
return mea;
})
);
}
private mapRow(row: Row) {
let channel = new Channel();
channel.id = Row.getColumn(row, 'Channel.Id');
channel.name = Row.getColumn(row, 'Channel.Name');
channel.channelGroupId = Row.getColumn(row, 'ChannelGroup.Id');
channel.axisType = Row.getColumn(row, 'LocalColumn.axistype'),
channel.isIndependent = Row.getColumn(row, 'LocalColumn.IndependentFlag') === '1';
let channelGroup = new ChannelGroup(
row.source,
Row.getColumn(row, 'ChannelGroup.Id'),
parseInt(Row.getColumn(row, 'ChannelGroup.SubMatrixNoRows'), 10));
channelGroup.name = Row.getColumn(row, 'ChannelGroup.Name');
return { meaId: Row.getColumn(row, 'Measurement.Id'), channelGroup: channelGroup, channel: channel };
}
}