rozetko
6 years ago
committed by
GitHub
25 changed files with 505 additions and 394 deletions
@ -1,244 +0,0 @@ |
|||||||
import { Collection, makeDBQ, SortingOrder } from '../services/data_service'; |
|
||||||
|
|
||||||
import { Metric } from 'grafana-datasource-kit'; |
|
||||||
|
|
||||||
import * as _ from 'lodash'; |
|
||||||
|
|
||||||
let db = makeDBQ(Collection.ANALYTIC_UNITS); |
|
||||||
|
|
||||||
|
|
||||||
export const ANALYTIC_UNIT_TYPES = { |
|
||||||
pattern: [ |
|
||||||
{ |
|
||||||
name: 'General', |
|
||||||
value: 'GENERAL' |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: 'Peak', |
|
||||||
value: 'PEAK' |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: 'Trough', |
|
||||||
value: 'TROUGH' |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: 'Jump', |
|
||||||
value: 'JUMP' |
|
||||||
}, |
|
||||||
{ |
|
||||||
name: 'Drop', |
|
||||||
value: 'DROP' |
|
||||||
} |
|
||||||
], |
|
||||||
threshold: [ |
|
||||||
{ |
|
||||||
name: 'Threshold', |
|
||||||
value: 'THRESHOLD' |
|
||||||
} |
|
||||||
] |
|
||||||
}; |
|
||||||
|
|
||||||
export enum DetectorType { |
|
||||||
PATTERN = 'pattern', |
|
||||||
THRESHOLD = 'threshold' |
|
||||||
}; |
|
||||||
|
|
||||||
export type AnalyticUnitId = string; |
|
||||||
export enum AnalyticUnitStatus { |
|
||||||
READY = 'READY', |
|
||||||
PENDING = 'PENDING', |
|
||||||
LEARNING = 'LEARNING', |
|
||||||
SUCCESS = 'SUCCESS', |
|
||||||
FAILED = 'FAILED' |
|
||||||
} |
|
||||||
|
|
||||||
export type FindManyQuery = { |
|
||||||
name?: string, |
|
||||||
grafanaUrl?: string, |
|
||||||
panelId?: string, |
|
||||||
type?: string, |
|
||||||
metric?: Metric, |
|
||||||
alert?: boolean, |
|
||||||
id?: AnalyticUnitId, |
|
||||||
lastDetectionTime?: number, |
|
||||||
status?: AnalyticUnitStatus, |
|
||||||
error?: string, |
|
||||||
labeledColor?: string, |
|
||||||
deletedColor?: string, |
|
||||||
detectorType?: DetectorType, |
|
||||||
visible?: boolean |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
export class AnalyticUnit { |
|
||||||
constructor( |
|
||||||
public name: string, |
|
||||||
public grafanaUrl: string, |
|
||||||
public panelId: string, |
|
||||||
public type: string, |
|
||||||
public metric?: Metric, |
|
||||||
public alert?: boolean, |
|
||||||
public id?: AnalyticUnitId, |
|
||||||
public lastDetectionTime?: number, |
|
||||||
public status?: AnalyticUnitStatus, |
|
||||||
public error?: string, |
|
||||||
public labeledColor?: string, |
|
||||||
public deletedColor?: string, |
|
||||||
public detectorType?: DetectorType, |
|
||||||
public visible?: boolean |
|
||||||
) { |
|
||||||
|
|
||||||
if(name === undefined) { |
|
||||||
throw new Error(`Missing field "name"`); |
|
||||||
} |
|
||||||
if(grafanaUrl === undefined) { |
|
||||||
throw new Error(`Missing field "grafanaUrl"`); |
|
||||||
} |
|
||||||
if(type === undefined) { |
|
||||||
throw new Error(`Missing field "type"`); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public toObject() { |
|
||||||
let metric; |
|
||||||
if(this.metric !== undefined) { |
|
||||||
metric = this.metric.toObject(); |
|
||||||
} |
|
||||||
|
|
||||||
return { |
|
||||||
_id: this.id, |
|
||||||
name: this.name, |
|
||||||
grafanaUrl: this.grafanaUrl, |
|
||||||
panelId: this.panelId, |
|
||||||
type: this.type, |
|
||||||
metric, |
|
||||||
alert: this.alert, |
|
||||||
lastDetectionTime: this.lastDetectionTime, |
|
||||||
status: this.status, |
|
||||||
error: this.error, |
|
||||||
labeledColor: this.labeledColor, |
|
||||||
deletedColor: this.deletedColor, |
|
||||||
detectorType: this.detectorType, |
|
||||||
visible: this.visible |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
public toPanelObject() { |
|
||||||
return { |
|
||||||
id: this.id, |
|
||||||
name: this.name, |
|
||||||
type: this.type, |
|
||||||
alert: this.alert, |
|
||||||
labeledColor: this.labeledColor, |
|
||||||
deletedColor: this.deletedColor, |
|
||||||
detectorType: this.detectorType, |
|
||||||
visible: this.visible |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
static fromObject(obj: any): AnalyticUnit { |
|
||||||
if(obj === undefined) { |
|
||||||
throw new Error('obj is undefined'); |
|
||||||
} |
|
||||||
let metric: Metric; |
|
||||||
if(obj.metric !== undefined) { |
|
||||||
metric = Metric.fromObject(obj.metric); |
|
||||||
} |
|
||||||
return new AnalyticUnit( |
|
||||||
obj.name, |
|
||||||
obj.grafanaUrl, |
|
||||||
obj.panelId, |
|
||||||
obj.type, |
|
||||||
metric, |
|
||||||
obj.alert, |
|
||||||
obj._id, |
|
||||||
obj.lastDetectionTime, |
|
||||||
obj.status as AnalyticUnitStatus, |
|
||||||
obj.error, |
|
||||||
obj.labeledColor, |
|
||||||
obj.deletedColor, |
|
||||||
obj.detectorType, |
|
||||||
obj.visible |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
export async function findById(id: AnalyticUnitId): Promise<AnalyticUnit> { |
|
||||||
let obj = await db.findOne(id); |
|
||||||
if(obj === null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return AnalyticUnit.fromObject(obj); |
|
||||||
} |
|
||||||
|
|
||||||
export async function findMany(query: FindManyQuery): Promise<AnalyticUnit[]> { |
|
||||||
const analyticUnits = await db.findMany(query, { |
|
||||||
createdAt: SortingOrder.ASCENDING, |
|
||||||
name: SortingOrder.ASCENDING |
|
||||||
}); |
|
||||||
if(analyticUnits === null) { |
|
||||||
return []; |
|
||||||
} |
|
||||||
return analyticUnits.map(AnalyticUnit.fromObject); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Creates and updates new unit.id |
|
||||||
* |
|
||||||
* @param unit to create |
|
||||||
* @returns unit.id |
|
||||||
*/ |
|
||||||
export async function create(unit: AnalyticUnit): Promise<AnalyticUnitId> { |
|
||||||
let obj = unit.toObject(); |
|
||||||
return db.insertOne(obj); |
|
||||||
} |
|
||||||
|
|
||||||
export async function remove(id: AnalyticUnitId): Promise<void> { |
|
||||||
// TODO: remove it`s segments
|
|
||||||
// TODO: remove it`s cache
|
|
||||||
await db.removeOne(id); |
|
||||||
} |
|
||||||
|
|
||||||
export async function update(id: AnalyticUnitId, unit: AnalyticUnit) { |
|
||||||
const updateObj = { |
|
||||||
name: unit.name, |
|
||||||
labeledColor: unit.labeledColor, |
|
||||||
deletedColor: unit.deletedColor, |
|
||||||
visible: unit.visible |
|
||||||
}; |
|
||||||
|
|
||||||
return db.updateOne(id, updateObj); |
|
||||||
} |
|
||||||
|
|
||||||
export async function setStatus(id: AnalyticUnitId, status: string, error?: string) { |
|
||||||
return db.updateOne(id, { status, error }); |
|
||||||
} |
|
||||||
|
|
||||||
export async function setDetectionTime(id: AnalyticUnitId, lastDetectionTime: number) { |
|
||||||
return db.updateOne(id, { lastDetectionTime }); |
|
||||||
} |
|
||||||
|
|
||||||
export async function setAlert(id: AnalyticUnitId, alert: boolean) { |
|
||||||
return db.updateOne(id, { alert }); |
|
||||||
} |
|
||||||
|
|
||||||
export async function setMetric(id: AnalyticUnitId, metric: Metric) { |
|
||||||
return db.updateOne(id, { metric }); |
|
||||||
} |
|
||||||
|
|
||||||
export function getDetectorByType(analyticUnitType: string): DetectorType { |
|
||||||
let detector; |
|
||||||
_.forOwn(ANALYTIC_UNIT_TYPES, (types, detectorType) => { |
|
||||||
if(_.find(types, { value: analyticUnitType }) !== undefined) { |
|
||||||
detector = detectorType; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
if(detector === undefined) { |
|
||||||
throw new Error(`Can't find detector for analytic unit of type "${analyticUnitType}"`); |
|
||||||
} |
|
||||||
return detector; |
|
||||||
} |
|
@ -0,0 +1,75 @@ |
|||||||
|
import { AnalyticUnitId, AnalyticUnitStatus, DetectorType } from './types'; |
||||||
|
|
||||||
|
import { Metric } from 'grafana-datasource-kit'; |
||||||
|
|
||||||
|
|
||||||
|
export abstract class AnalyticUnit { |
||||||
|
constructor( |
||||||
|
public name: string, |
||||||
|
public grafanaUrl: string, |
||||||
|
public panelId: string, |
||||||
|
// TODO: enum type
|
||||||
|
// TODO: type -> subType
|
||||||
|
public type: string, |
||||||
|
public metric?: Metric, |
||||||
|
public alert?: boolean, |
||||||
|
public id?: AnalyticUnitId, |
||||||
|
public lastDetectionTime?: number, |
||||||
|
public status?: AnalyticUnitStatus, |
||||||
|
public error?: string, |
||||||
|
public labeledColor?: string, |
||||||
|
public deletedColor?: string, |
||||||
|
// TODO: detectorType -> type
|
||||||
|
public detectorType?: DetectorType, |
||||||
|
public visible?: boolean |
||||||
|
) { |
||||||
|
|
||||||
|
if(name === undefined) { |
||||||
|
throw new Error(`Missing field "name"`); |
||||||
|
} |
||||||
|
if(grafanaUrl === undefined) { |
||||||
|
throw new Error(`Missing field "grafanaUrl"`); |
||||||
|
} |
||||||
|
if(type === undefined) { |
||||||
|
throw new Error(`Missing field "type"`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public toObject() { |
||||||
|
let metric; |
||||||
|
if(this.metric !== undefined) { |
||||||
|
metric = this.metric.toObject(); |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
_id: this.id, |
||||||
|
name: this.name, |
||||||
|
grafanaUrl: this.grafanaUrl, |
||||||
|
panelId: this.panelId, |
||||||
|
type: this.type, |
||||||
|
metric, |
||||||
|
alert: this.alert, |
||||||
|
lastDetectionTime: this.lastDetectionTime, |
||||||
|
status: this.status, |
||||||
|
error: this.error, |
||||||
|
labeledColor: this.labeledColor, |
||||||
|
deletedColor: this.deletedColor, |
||||||
|
detectorType: this.detectorType, |
||||||
|
visible: this.visible |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
public toPanelObject() { |
||||||
|
return { |
||||||
|
id: this.id, |
||||||
|
name: this.name, |
||||||
|
type: this.type, |
||||||
|
alert: this.alert, |
||||||
|
labeledColor: this.labeledColor, |
||||||
|
deletedColor: this.deletedColor, |
||||||
|
detectorType: this.detectorType, |
||||||
|
visible: this.visible |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
import { createAnalyticUnitFromObject } from './utils'; |
||||||
|
import { AnalyticUnit } from './analytic_unit_model'; |
||||||
|
import { AnalyticUnitId, FindManyQuery } from './types'; |
||||||
|
import { Collection, makeDBQ, SortingOrder } from '../../services/data_service'; |
||||||
|
|
||||||
|
import { Metric } from 'grafana-datasource-kit'; |
||||||
|
|
||||||
|
import * as _ from 'lodash'; |
||||||
|
|
||||||
|
|
||||||
|
const db = makeDBQ(Collection.ANALYTIC_UNITS); |
||||||
|
|
||||||
|
export async function findById(id: AnalyticUnitId): Promise<AnalyticUnit> { |
||||||
|
let obj = await db.findOne(id); |
||||||
|
if (obj === null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return createAnalyticUnitFromObject(obj); |
||||||
|
} |
||||||
|
|
||||||
|
export async function findMany(query: FindManyQuery): Promise<AnalyticUnit[]> { |
||||||
|
const analyticUnits = await db.findMany(query, { |
||||||
|
createdAt: SortingOrder.ASCENDING, |
||||||
|
name: SortingOrder.ASCENDING |
||||||
|
}); |
||||||
|
if (analyticUnits === null) { |
||||||
|
return []; |
||||||
|
} |
||||||
|
return analyticUnits.map(createAnalyticUnitFromObject); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Creates and updates new unit.id |
||||||
|
* |
||||||
|
* @param unit to create |
||||||
|
* @returns unit.id |
||||||
|
*/ |
||||||
|
export async function create(unit: AnalyticUnit): Promise<AnalyticUnitId> { |
||||||
|
let obj = unit.toObject(); |
||||||
|
return db.insertOne(obj); |
||||||
|
} |
||||||
|
|
||||||
|
export async function remove(id: AnalyticUnitId): Promise<void> { |
||||||
|
// TODO: remove it`s segments
|
||||||
|
// TODO: remove it`s cache
|
||||||
|
await db.removeOne(id); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Changes values of analytic unit fields to according values of obj |
||||||
|
* |
||||||
|
* @param id analytic unit id |
||||||
|
* @param obj object with keys and values which need to be updated in analytic unit |
||||||
|
*/ |
||||||
|
export async function update(id: AnalyticUnitId, obj: any) { |
||||||
|
const analyticUnitObj = await db.findOne(id); |
||||||
|
if(analyticUnitObj === null) { |
||||||
|
throw new Error(`Analytic unit ${id} doesn't exist`); |
||||||
|
} |
||||||
|
|
||||||
|
const analyticUnit = createAnalyticUnitFromObject(analyticUnitObj); |
||||||
|
let updateObj: any = analyticUnit.toPanelObject(); |
||||||
|
delete updateObj.id; |
||||||
|
updateObj = _.mapValues(updateObj, (value, key) => { |
||||||
|
if(_.has(obj, key)) { |
||||||
|
return obj[key]; |
||||||
|
} |
||||||
|
return value; |
||||||
|
}); |
||||||
|
|
||||||
|
return db.updateOne(id, updateObj); |
||||||
|
} |
||||||
|
|
||||||
|
export async function setStatus(id: AnalyticUnitId, status: string, error?: string) { |
||||||
|
return db.updateOne(id, { status, error }); |
||||||
|
} |
||||||
|
|
||||||
|
export async function setDetectionTime(id: AnalyticUnitId, lastDetectionTime: number) { |
||||||
|
return db.updateOne(id, { lastDetectionTime }); |
||||||
|
} |
||||||
|
|
||||||
|
export async function setAlert(id: AnalyticUnitId, alert: boolean) { |
||||||
|
return db.updateOne(id, { alert }); |
||||||
|
} |
||||||
|
|
||||||
|
export async function setMetric(id: AnalyticUnitId, metric: Metric) { |
||||||
|
return db.updateOne(id, { metric }); |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
import { createAnalyticUnitFromObject, getDetectorByType } from './utils'; |
||||||
|
import { AnalyticUnitId, AnalyticUnitStatus, DetectorType, ANALYTIC_UNIT_TYPES } from './types'; |
||||||
|
import { AnalyticUnit } from './analytic_unit_model'; |
||||||
|
import { PatternAnalyticUnit } from './pattern_analytic_unit_model'; |
||||||
|
import { ThresholdAnalyticUnit } from './threshold_analytic_unit_model'; |
||||||
|
import { |
||||||
|
findById, |
||||||
|
findMany, |
||||||
|
create, |
||||||
|
remove, |
||||||
|
update, |
||||||
|
setStatus, |
||||||
|
setDetectionTime, |
||||||
|
setAlert, |
||||||
|
setMetric |
||||||
|
} from './db'; |
||||||
|
|
||||||
|
|
||||||
|
export { |
||||||
|
AnalyticUnit, PatternAnalyticUnit, ThresholdAnalyticUnit, |
||||||
|
AnalyticUnitId, AnalyticUnitStatus, DetectorType, ANALYTIC_UNIT_TYPES, |
||||||
|
createAnalyticUnitFromObject, getDetectorByType, |
||||||
|
findById, findMany, |
||||||
|
create, remove, update, |
||||||
|
setStatus, setDetectionTime, setAlert, setMetric |
||||||
|
}; |
@ -0,0 +1,78 @@ |
|||||||
|
import { AnalyticUnit } from './analytic_unit_model'; |
||||||
|
import { AnalyticUnitId, AnalyticUnitStatus, DetectorType } from './types'; |
||||||
|
|
||||||
|
import { Metric } from 'grafana-datasource-kit'; |
||||||
|
|
||||||
|
|
||||||
|
export class PatternAnalyticUnit extends AnalyticUnit { |
||||||
|
constructor( |
||||||
|
name: string, |
||||||
|
grafanaUrl: string, |
||||||
|
panelId: string, |
||||||
|
type: string, |
||||||
|
metric?: Metric, |
||||||
|
alert?: boolean, |
||||||
|
id?: AnalyticUnitId, |
||||||
|
lastDetectionTime?: number, |
||||||
|
status?: AnalyticUnitStatus, |
||||||
|
error?: string, |
||||||
|
labeledColor?: string, |
||||||
|
deletedColor?: string, |
||||||
|
visible?: boolean |
||||||
|
) { |
||||||
|
super( |
||||||
|
name, |
||||||
|
grafanaUrl, |
||||||
|
panelId, |
||||||
|
type, |
||||||
|
metric, |
||||||
|
alert, |
||||||
|
id, |
||||||
|
lastDetectionTime, |
||||||
|
status, |
||||||
|
error, |
||||||
|
labeledColor, |
||||||
|
deletedColor, |
||||||
|
DetectorType.PATTERN, |
||||||
|
visible |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
toObject() { |
||||||
|
const baseObject = super.toObject(); |
||||||
|
return { |
||||||
|
...baseObject |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
toPanelObject() { |
||||||
|
const baseObject = super.toPanelObject(); |
||||||
|
return { |
||||||
|
...baseObject |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
static fromObject(obj: any) { |
||||||
|
// TODO: remove duplication
|
||||||
|
let metric: Metric; |
||||||
|
if(obj.metric !== undefined) { |
||||||
|
metric = Metric.fromObject(obj.metric); |
||||||
|
} |
||||||
|
|
||||||
|
return new PatternAnalyticUnit( |
||||||
|
obj.name, |
||||||
|
obj.grafanaUrl, |
||||||
|
obj.panelId, |
||||||
|
obj.type, |
||||||
|
metric, |
||||||
|
obj.alert, |
||||||
|
obj._id, |
||||||
|
obj.lastDetectionTime, |
||||||
|
obj.status, |
||||||
|
obj.error, |
||||||
|
obj.labeledColor, |
||||||
|
obj.deletedColor, |
||||||
|
obj.visible |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
import { AnalyticUnit } from './analytic_unit_model'; |
||||||
|
import { AnalyticUnitId, AnalyticUnitStatus, DetectorType } from './types'; |
||||||
|
|
||||||
|
import { Metric } from 'grafana-datasource-kit'; |
||||||
|
|
||||||
|
|
||||||
|
export enum Condition { |
||||||
|
ABOVE = '>', |
||||||
|
ABOVE_OR_EQUAL = '>=', |
||||||
|
EQUAL = '=', |
||||||
|
LESS_OR_EQUAL = '<=', |
||||||
|
LESS = '<', |
||||||
|
NO_DATA = 'NO_DATA' |
||||||
|
}; |
||||||
|
|
||||||
|
export class ThresholdAnalyticUnit extends AnalyticUnit { |
||||||
|
constructor( |
||||||
|
name: string, |
||||||
|
grafanaUrl: string, |
||||||
|
panelId: string, |
||||||
|
type: string, |
||||||
|
public value: number, |
||||||
|
public condition: Condition, |
||||||
|
metric?: Metric, |
||||||
|
alert?: boolean, |
||||||
|
id?: AnalyticUnitId, |
||||||
|
lastDetectionTime?: number, |
||||||
|
status?: AnalyticUnitStatus, |
||||||
|
error?: string, |
||||||
|
labeledColor?: string, |
||||||
|
deletedColor?: string, |
||||||
|
visible?: boolean |
||||||
|
) { |
||||||
|
super( |
||||||
|
name, |
||||||
|
grafanaUrl, |
||||||
|
panelId, |
||||||
|
type, |
||||||
|
metric, |
||||||
|
alert, |
||||||
|
id, |
||||||
|
lastDetectionTime, |
||||||
|
status, |
||||||
|
error, |
||||||
|
labeledColor, |
||||||
|
deletedColor, |
||||||
|
DetectorType.THRESHOLD, |
||||||
|
visible |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
toObject() { |
||||||
|
const baseObject = super.toObject(); |
||||||
|
return { |
||||||
|
...baseObject, |
||||||
|
value: this.value, |
||||||
|
condition: this.condition |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
toPanelObject() { |
||||||
|
const baseObject = super.toPanelObject(); |
||||||
|
return { |
||||||
|
...baseObject, |
||||||
|
value: this.value, |
||||||
|
condition: this.condition |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
static fromObject(obj: any) { |
||||||
|
// TODO: remove duplication
|
||||||
|
let metric: Metric; |
||||||
|
if (obj.metric !== undefined) { |
||||||
|
metric = Metric.fromObject(obj.metric); |
||||||
|
} |
||||||
|
|
||||||
|
return new ThresholdAnalyticUnit( |
||||||
|
obj.name, |
||||||
|
obj.grafanaUrl, |
||||||
|
obj.panelId, |
||||||
|
obj.type, |
||||||
|
obj.value, |
||||||
|
obj.condition, |
||||||
|
metric, |
||||||
|
obj.alert, |
||||||
|
obj._id, |
||||||
|
obj.lastDetectionTime, |
||||||
|
obj.status, |
||||||
|
obj.error, |
||||||
|
obj.labeledColor, |
||||||
|
obj.deletedColor, |
||||||
|
obj.visible |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
import { Metric } from 'grafana-datasource-kit'; |
||||||
|
|
||||||
|
|
||||||
|
export type AnalyticUnitId = string; |
||||||
|
export enum AnalyticUnitStatus { |
||||||
|
READY = 'READY', |
||||||
|
PENDING = 'PENDING', |
||||||
|
LEARNING = 'LEARNING', |
||||||
|
SUCCESS = 'SUCCESS', |
||||||
|
FAILED = 'FAILED' |
||||||
|
}; |
||||||
|
|
||||||
|
export type FindManyQuery = { |
||||||
|
name?: string, |
||||||
|
grafanaUrl?: string, |
||||||
|
panelId?: string, |
||||||
|
type?: string, |
||||||
|
metric?: Metric, |
||||||
|
alert?: boolean, |
||||||
|
id?: AnalyticUnitId, |
||||||
|
lastDetectionTime?: number, |
||||||
|
status?: AnalyticUnitStatus, |
||||||
|
error?: string, |
||||||
|
labeledColor?: string, |
||||||
|
deletedColor?: string, |
||||||
|
detectorType?: DetectorType, |
||||||
|
visible?: boolean |
||||||
|
}; |
||||||
|
|
||||||
|
export const ANALYTIC_UNIT_TYPES = { |
||||||
|
pattern: [ |
||||||
|
{ |
||||||
|
name: 'General', |
||||||
|
value: 'GENERAL' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: 'Peak', |
||||||
|
value: 'PEAK' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: 'Trough', |
||||||
|
value: 'TROUGH' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: 'Jump', |
||||||
|
value: 'JUMP' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: 'Drop', |
||||||
|
value: 'DROP' |
||||||
|
} |
||||||
|
], |
||||||
|
threshold: [ |
||||||
|
{ |
||||||
|
name: 'Threshold', |
||||||
|
value: 'THRESHOLD' |
||||||
|
} |
||||||
|
] |
||||||
|
}; |
||||||
|
|
||||||
|
export enum DetectorType { |
||||||
|
PATTERN = 'pattern', |
||||||
|
THRESHOLD = 'threshold' |
||||||
|
}; |
@ -0,0 +1,38 @@ |
|||||||
|
import { DetectorType, ANALYTIC_UNIT_TYPES } from './types'; |
||||||
|
import { AnalyticUnit } from './analytic_unit_model'; |
||||||
|
import { PatternAnalyticUnit } from './pattern_analytic_unit_model'; |
||||||
|
import { ThresholdAnalyticUnit } from './threshold_analytic_unit_model'; |
||||||
|
|
||||||
|
import * as _ from 'lodash'; |
||||||
|
|
||||||
|
|
||||||
|
export function createAnalyticUnitFromObject(obj: any): AnalyticUnit { |
||||||
|
if (obj === undefined) { |
||||||
|
throw new Error('obj is undefined'); |
||||||
|
} |
||||||
|
|
||||||
|
const detectorType: DetectorType = obj.detectorType; |
||||||
|
switch (detectorType) { |
||||||
|
case DetectorType.PATTERN: |
||||||
|
return PatternAnalyticUnit.fromObject(obj); |
||||||
|
case DetectorType.THRESHOLD: |
||||||
|
return ThresholdAnalyticUnit.fromObject(obj); |
||||||
|
|
||||||
|
default: |
||||||
|
throw new Error(`Can't create analytic unit with type "${detectorType}"`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function getDetectorByType(analyticUnitType: string): DetectorType { |
||||||
|
let detector; |
||||||
|
_.forOwn(ANALYTIC_UNIT_TYPES, (types, detectorType) => { |
||||||
|
if(_.find(types, { value: analyticUnitType }) !== undefined) { |
||||||
|
detector = detectorType; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if(detector === undefined) { |
||||||
|
throw new Error(`Can't find detector for analytic unit of type "${analyticUnitType}"`); |
||||||
|
} |
||||||
|
return detector; |
||||||
|
} |
@ -1,71 +0,0 @@ |
|||||||
import { AnalyticUnitId } from './analytic_unit_model'; |
|
||||||
|
|
||||||
import { Collection, makeDBQ } from '../services/data_service'; |
|
||||||
|
|
||||||
import * as _ from 'lodash'; |
|
||||||
|
|
||||||
let db = makeDBQ(Collection.THRESHOLD); |
|
||||||
|
|
||||||
|
|
||||||
export enum Condition { |
|
||||||
ABOVE = '>', |
|
||||||
ABOVE_OR_EQUAL = '>=', |
|
||||||
EQUAL = '=', |
|
||||||
LESS_OR_EQUAL = '<=', |
|
||||||
LESS = '<', |
|
||||||
NO_DATA = 'NO_DATA' |
|
||||||
}; |
|
||||||
|
|
||||||
export class Threshold { |
|
||||||
constructor( |
|
||||||
public id: AnalyticUnitId, |
|
||||||
public value: number, |
|
||||||
public condition: Condition |
|
||||||
) { |
|
||||||
if(id === undefined) { |
|
||||||
throw new Error('id is undefined'); |
|
||||||
} |
|
||||||
if(value === undefined) { |
|
||||||
throw new Error('condition is undefined'); |
|
||||||
} |
|
||||||
if(condition === undefined) { |
|
||||||
throw new Error('condition is undefined'); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public toObject() { |
|
||||||
return { |
|
||||||
_id: this.id, |
|
||||||
value: this.value, |
|
||||||
condition: this.condition |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
static fromObject(obj: any): Threshold { |
|
||||||
if(obj === undefined) { |
|
||||||
throw new Error('obj is undefined'); |
|
||||||
} |
|
||||||
return new Threshold(obj._id, +obj.value, obj.condition); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
export async function findOne(id: AnalyticUnitId): Promise<Threshold | null> { |
|
||||||
const threshold = await db.findOne(id); |
|
||||||
if(threshold === null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return Threshold.fromObject(threshold); |
|
||||||
} |
|
||||||
|
|
||||||
export async function updateThreshold(id: AnalyticUnitId, value: number, condition: Condition) { |
|
||||||
let threshold = await db.findOne(id); |
|
||||||
if(threshold === null) { |
|
||||||
threshold = new Threshold(id, value, condition); |
|
||||||
return db.insertOne(threshold.toObject()); |
|
||||||
} |
|
||||||
return db.updateOne(id, { value, condition }); |
|
||||||
} |
|
||||||
|
|
||||||
export async function removeThreshold(id: AnalyticUnitId) { |
|
||||||
return db.removeOne(id); |
|
||||||
} |
|
@ -1,44 +0,0 @@ |
|||||||
import * as AnalyticsController from '../controllers/analytics_controller'; |
|
||||||
|
|
||||||
import { AnalyticUnitId } from '../models/analytic_unit_model'; |
|
||||||
import * as Threshold from '../models/threshold_model'; |
|
||||||
|
|
||||||
import * as Router from 'koa-router'; |
|
||||||
import * as _ from 'lodash'; |
|
||||||
|
|
||||||
|
|
||||||
async function getThresholds(ctx: Router.IRouterContext) { |
|
||||||
|
|
||||||
const ids: AnalyticUnitId[] = ctx.request.query.ids.split(','); |
|
||||||
|
|
||||||
if(ids === undefined) { |
|
||||||
throw new Error('analyticUnitIds (ids) are missing'); |
|
||||||
} |
|
||||||
|
|
||||||
const thresholds = await Promise.all( |
|
||||||
_.map(ids, id => Threshold.findOne(id)) |
|
||||||
); |
|
||||||
|
|
||||||
ctx.response.body = { thresholds }; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
async function updateThreshold(ctx: Router.IRouterContext) { |
|
||||||
const { |
|
||||||
id, value, condition |
|
||||||
} = ctx.request.body as { |
|
||||||
id: AnalyticUnitId, value: number, condition: Threshold.Condition |
|
||||||
}; |
|
||||||
|
|
||||||
await AnalyticsController.updateThreshold(id, value, condition); |
|
||||||
|
|
||||||
ctx.response.body = { |
|
||||||
code: 200, |
|
||||||
message: 'Success' |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
export const router = new Router(); |
|
||||||
|
|
||||||
router.get('/', getThresholds); |
|
||||||
router.patch('/', updateThreshold); |
|
Loading…
Reference in new issue