Services/Frames.js

/**Copyright (c) 2009-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.**/
"use strict";const deepcopy=require("deepcopy"),Database=require("../Utils/Database"),filterTemplate=require("../queryTemplates/filter.json"),Elasticsearch=require("../Utils/Elasticsearch"),Validator=require("../Utils/Validator"),InternalServerError=require("../Errors/InternalServerError"),InvalidInputError=require("../Errors/InvalidInputError"),BadRequestError=require("../Errors/BadRequestError"),Calibration=require("./Calibration"),Utils=require("../Utils/Utils"),winston=require("winston"),logger=winston.createLogger({transports:[new winston.transports.Console({timestamp:!0,level:"info"})],exitOnError:!1});
/** 
 * Class which defines Frames
 * @memberof mdxWebApiCore.Services
 * */
class Frames{static#e=25;static#t=1e3;static#r=100;static#a=.8;async#s(e,{fromTimestamp:t,toTimestamp:r,sensorId:a,objectId:s,maxResultSize:i,minConfidence:n}){const o=e.getConfigs().get("rawIndex");let m=deepcopy(filterTemplate);m.query.bool.must.push({term:{"sensorId.keyword":a}}),m.query.bool.must.push({range:{timestamp:{gte:t,lte:r}}}),null!=s&&m.query.bool.must.push({nested:{path:"objects",query:{bool:{must:[{term:{"objects.id.keyword":s}}]}}}}),m.aggs={objects:{nested:{path:"objects"},aggs:{objectsFilter:{filter:{bool:{filter:[{range:{"objects.confidence":{gte:n}}}]}},aggs:{objectIds:{terms:{field:"objects.id.keyword",size:null!=s?1:i},aggs:{maxConfidenceDetection:{top_hits:{sort:[{"objects.confidence":{order:"desc"}}],_source:{includes:["objects.id","objects.bbox","objects.confidence","objects.embedding.vector"]},size:1}}}}}}}}},null!=s&&m.aggs.objects.aggs.objectsFilter.filter.bool.filter.push({term:{"objects.id.keyword":s}});let l={index:o,body:m,size:0},d=await Elasticsearch.getSearchResults(e.getClient(),l,!1),u=new Map;if(!d.indexAbsent)for(let e of d.body.aggregations.objects.objectsFilter.objectIds.buckets){let t=e.maxConfidenceDetection.hits.hits[0]._id,r=e.maxConfidenceDetection.hits.hits[0]._source;if(u.has(t)){let e=u.get(t);e.push(r),u.set(t,e)}else u.set(t,[r])}return u}async#i(e,t){if(0==t.length)return new Map;let r={index:e.getConfigs().get("rawIndex"),body:{query:{ids:{values:t}}},size:t.length},a=await Elasticsearch.getSearchResults(e.getClient(),r,!1),s=new Map;if(!a.indexAbsent)for(let e of a.body.hits.hits)s.set(e._id,e._source);return s}async#n(e,{sensorId:t,objectId:r,frameId:a}){const s=e.getConfigs().get("rawIndex");let i=deepcopy(filterTemplate);i.query.bool.must.push({term:{"sensorId.keyword":t}}),i.query.bool.must.push({term:{"id.keyword":a}}),i.query.bool.must.push({nested:{path:"objects",query:{bool:{must:[{term:{"objects.id.keyword":r}}]}}}});let n={index:s,body:i,sort:"timestamp:desc",_sourceIncludes:["timestamp"],size:1},o=await Elasticsearch.getSearchResults(e.getClient(),n,!1);if(!o.indexAbsent)return o=Elasticsearch.searchResultFormatter(o.body),0==o.length?null:o[0].timestamp}async#o(e,{sensorId:t,objectId:r,timestamp:a}){const s=e.getConfigs().get("rawIndex");let i=deepcopy(filterTemplate);i.query.bool.must.push({term:{"sensorId.keyword":t}}),i.query.bool.must.push({term:{timestamp:a}}),i.aggs={objects:{nested:{path:"objects"},aggs:{objectsFilter:{filter:{bool:{filter:[{term:{"objects.id.keyword":r}}]}},aggs:{objectDoc:{top_hits:{_source:{includes:["objects.embedding.vector"]},size:1}}}}}}};let n={index:s,body:i,size:0},o=await Elasticsearch.getSearchResults(e.getClient(),n,!1),m=new Array;return o.indexAbsent||(o=Elasticsearch.searchResultFormatter(o.body.aggregations.objects.objectsFilter.objectDoc),o.length>0&&(m=null!=o[0].embedding?o[0].embedding.vector:null)),m}
/** 
     * returns an object containing an array of detected objects. Only the data point corresponding to the max confidence of each object id will be present in the array.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {?string} [input.objectId=null] - objectId and maxResultSize can't occur together.
     * @param {string} input.fromTimestamp
     * @param {string} input.toTimestamp
     * @param {number} [input.maxResultSize=100] - maxResultSize must be an integer. objectId and maxResultSize can't occur together.
     * @param {number} [input.minConfidence=0.80]
     * @returns {Promise<Object>} An object containing an array of detected objects is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", fromTimestamp: "2023-01-12T11:20:10.000Z", toTimestamp: "2023-01-12T14:20:10.000Z"};
     * let framesMetadata = new mdx.Services.Frames();
     * let objects = await framesMetadata.getMaxConfidenceDetectionOfObjects(elastic, input);
     */async getMaxConfidenceDetectionOfObjects(e,t){const r={type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},objectId:{type:["string","null"],default:null,minLength:1,errorMessage:{minLength:"objectId should have atleast 1 character."}},fromTimestamp:{type:"string"},toTimestamp:{type:"string"},maxResultSize:{type:"integer",minimum:1,maximum:Frames.#r,default:Frames.#r,errorMessage:{type:"maxResultSize is not an integer.",minimum:"maxResultSize can have a minimum value of 1.",maximum:`maxResultSize can have a maximum value of ${Frames.#r}.`}},minConfidence:{type:"number",minimum:0,maximum:1,default:Frames.#a,errorMessage:{type:"minConfidence is not a number.",minimum:"minConfidence can have a minimum value of 0.",maximum:"minConfidence can have a maximum value of 1."}}},required:["sensorId","fromTimestamp","toTimestamp"],not:{required:["objectId","maxResultSize"]},errorMessage:{required:"Input should have required properties 'sensorId', 'fromTimestamp' and 'toTimestamp'.",not:"Input cannot have both 'objectId' and 'maxResultSize'."}};let a=Validator.validateJsonSchema(t,r);if(!a.valid)throw new BadRequestError(a.reason);let s=Validator.isValidTimeRange(t.fromTimestamp,t.toTimestamp);if(!s.valid)throw new InvalidInputError(s.reason);if("maxResultSize"in t&&!Number.isFinite(t.maxResultSize))throw new InvalidInputError("maxResultSize is not a finite integer.");if("minConfidence"in t&&!Number.isFinite(t.minConfidence))throw new InvalidInputError("minConfidence is not a finite number.");let i=new Array;if("Elasticsearch"===e.getName()){let r=await this.#s(e,t),a=await this.#i(e,Array.from(r.keys()));for(let[e,t]of a.entries()){let a=r.get(e);for(let e of a)i.push({frameId:t.id,sensorId:t.sensorId,timestamp:t.timestamp,objectId:e.id,bbox:e.bbox,confidence:e.confidence,embedding:null!=e.embedding?e.embedding.vector:null})}return{objects:i}}throw new InternalServerError(`Invalid database: ${e.getName()}.`)}
/** 
     * returns the timestamp of the latest occurance of objectId in a frameId of a sensor.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {string} input.objectId
     * @param {string} input.frameId
     * @returns {Promise<?string>} Timestamp of the frame is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", objectId: "120", frameId: "2200"};
     * let framesMetadata = new mdx.Services.Frames();
     * let timestampOfFrame = await framesMetadata.getLatestTimestampOfFrameWithObject(elastic, input);
     */async getLatestTimestampOfFrameWithObject(e,t){let r=Validator.validateJsonSchema(t,{type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},objectId:{type:"string",minLength:1,errorMessage:{minLength:"objectId should have atleast 1 character."}},frameId:{type:"string",minLength:1,errorMessage:{minLength:"frameId should have atleast 1 character."}}},required:["sensorId","objectId","frameId"],errorMessage:{required:"Input should have required properties 'sensorId', 'objectId' and 'frameId'."}});if(!r.valid)throw new BadRequestError(r.reason);let a=null;if("Elasticsearch"===e.getName())return a=await this.#n(e,t),a;throw new InternalServerError(`Invalid database: ${e.getName()}.`)}
/** 
     * returns embedding of an objectId.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {string} input.objectId
     * @param {string} input.timestamp
     * @returns {Promise<?Array<number>>} Embedding of an objectId is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", objectId: "120", timestamp: "2023-01-12T11:20:10.000Z"};
     * let framesMetadata = new mdx.Services.Frames();
     * let embedding = await framesMetadata.getEmbedding(elastic, input);
     */async getEmbedding(e,t){let r=Validator.validateJsonSchema(t,{type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},objectId:{type:"string",minLength:1,errorMessage:{minLength:"objectId should have atleast 1 character."}},timestamp:{type:"string"}},required:["sensorId","objectId","timestamp"],errorMessage:{required:"Input should have required properties 'sensorId', 'objectId' and 'timestamp'."}});if(!r.valid)throw new BadRequestError(r.reason);if(!Validator.isValidISOTimestamp(t.timestamp))throw new InvalidInputError("Invalid timestamp.");let a=new Array;if("Elasticsearch"===e.getName())return a=this.#o(e,t),a;throw new InternalServerError(`Invalid database: ${e.getName()}.`)}async#m(e,{sensorId:t,fromTimestamp:r,toTimestamp:a}){const s=`${e.getConfigs().get("indexPrefix")}${Elasticsearch.getIndex("frames")}`;let i=deepcopy(filterTemplate);i.query.bool.must.push({range:{timestamp:{lte:a,gte:r}}}),i.query.bool.must.push({term:{"sensorId.keyword":t}});let n={index:s,body:i,size:1,sort:"timestamp:desc",_sourceIncludes:["id","timestamp","socialDistancing.clusters"]};return await Elasticsearch.getSearchResults(e.getClient(),n,!1)}
/** 
     * returns details of proximity clusters.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {string} input.fromTimestamp
     * @param {string} input.toTimestamp
     * @returns {Promise<Object>} An object containing details of proximity clusters is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", fromTimestamp: "2023-01-12T11:20:10.000Z", toTimestamp: "2023-01-12T14:20:10.000Z"};
     * let framesMetadata = new mdx.Services.Frames();
     * let proximityClusterResult = await framesMetadata.getProximityClusters(elastic, input);
     */async getProximityClusters(e,t){let r=Validator.validateJsonSchema(t,{type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},fromTimestamp:{type:"string"},toTimestamp:{type:"string"}},required:["sensorId","fromTimestamp","toTimestamp"],errorMessage:{required:"Input should have required properties 'sensorId', 'fromTimestamp' and 'toTimestamp'."}});if(!r.valid)throw new BadRequestError(r.reason);let a=Validator.isValidTimeRange(t.fromTimestamp,t.toTimestamp);if(!a.valid)throw new InvalidInputError(a.reason);let s={id:null,timestamp:null,clusters:new Array};if("Elasticsearch"===e.getName()){let r=await this.#m(e,t);return r.indexAbsent||(r=Elasticsearch.searchResultFormatter(r.body),r.length>0&&(s.id=r[0].id,s.timestamp=r[0].timestamp,s.clusters=r[0].socialDistancing.clusters)),s}throw new InternalServerError(`Invalid database: ${e.getName()}.`)}async#l(e,{sensorId:t,timestamp:r}){let a=null;if("Elasticsearch"===e.getName()){const s=e.getConfigs().get("rawIndex");let i=deepcopy(filterTemplate);i.query.bool.must.push({term:{"sensorId.keyword":t}}),i.query.bool.must.push({range:{timestamp:{lte:r}}});let n={index:s,body:i,size:1,sort:"timestamp:desc",_sourceIncludes:["id","timestamp"]},o=await Elasticsearch.getSearchResults(e.getClient(),n,!1);return o.indexAbsent?logger.info("[DATA] Raw index is not present."):(o=Elasticsearch.searchResultFormatter(o.body),0==o.length?logger.info(`[DATA] Raw data is not present for sensor: ${t}.`):a=o[0]),a}throw new InternalServerError(`Invalid database: ${e.getName()}.`)}
/** 
     * returns an object containing pts.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {string} [input.timestamp] - Either timestamp or frameId should be present.
     * @param {number} [input.frameId] - frameId must be an integer. Either timestamp or frameId should be present.
     * @returns {Promise<Object>} An object containing pts is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", frameId: 2200};
     * let framesMetadata = new mdx.Services.Frames();
     * let pts = await framesMetadata.getPts(elastic, input);
     */async getPts(e,t){let r=Validator.validateJsonSchema(t,{type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},timestamp:{type:"string"},frameId:{type:"integer"}},required:["sensorId"],oneOf:[{required:["timestamp"]},{required:["frameId"]}],errorMessage:{required:"Input should have required property 'sensorId'.",oneOf:"Input should have either 'timestamp' or 'frameId'."}});if(!r.valid)throw new BadRequestError(r.reason);if("timestamp"in t){if(!Validator.isValidISOTimestamp(t.timestamp))throw new InvalidInputError("Invalid timestamp.")}else if(!Number.isFinite(t.frameId))throw new InvalidInputError("frameId is not a finite integer.");let a=new Calibration,{calibration:s}=await a.getCalibration(e,{sensorId:t.sensorId}),i=s.sensors[0],n=null,o=null;for(let e of i.attributes)"fps"===e.name?""!==e.value&&(n=parseInt(e.value,10)):"source"===e.name&&""!==e.value&&(o=e.value);if(null==o)throw new InvalidInputError(`source of the sensor is not defined in calibration. Update the calibration of sensorId: ${t.sensorId}.`);if("nvstreamer"!==o)throw new InvalidInputError("Pts can be calculated only for 'nvstreamer' source.");if(null==n)throw new InvalidInputError(`fps of the sensor is not defined in calibration. Update the calibration of sensorId: ${t.sensorId}.`);if("frameId"in t)return{pts:Math.floor(t.frameId/n*1e3)};{let r=null,a=await this.#l(e,t);if(null!=a){let e=parseInt(a.id,10),s=Math.floor(e/n*1e3),i=Utils.tsCompare(t.timestamp,"==",a.timestamp),o=Utils.tsCompare(t.timestamp,"<",a.timestamp),m=Utils.tsCompare(t.timestamp,">",a.timestamp);i?r=s:o?r=s-(new Date(a.timestamp)-new Date(t.timestamp)):m&&(r=s+(new Date(t.timestamp)-new Date(a.timestamp)))}return{pts:r}}}async#d(e,{sensorId:t,frameId:r,timestamp:a,fromTimestamp:s,toTimestamp:i,maxResultSize:n,type:o}){const m="raw"===o?e.getConfigs().get("rawIndex"):`${e.getConfigs().get("indexPrefix")}${Elasticsearch.getIndex("frames")}`;let l=deepcopy(filterTemplate);l.query.bool.must.push({term:{"sensorId.keyword":t}}),null!=r?l.query.bool.must.push({term:{"id.keyword":r}}):null!=a?l.query.bool.must.push({term:{timestamp:a}}):l.query.bool.must.push({range:{timestamp:{lte:i,gte:s}}});let d={index:m,body:l,sort:"timestamp:desc",size:n};return"raw"===o?d._sourceIncludes=["version","id","timestamp","sensorId","objects"]:d._sourceExcludes=["type"],await Elasticsearch.getSearchResults(e.getClient(),d,!1)}
/** 
     * returns an object containing an array of frames.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {string} [input.frameId] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present. frameId can't occur together with maxResultSize.
     * @param {string} [input.timestamp] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present. timestamp can't occur together with maxResultSize.
     * @param {string} [input.fromTimestamp] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present.
     * @param {string} [input.toTimestamp] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present.
     * @param {number} [input.maxResultSize=25] - maxResultSize must be an integer. maxResultSize can't occur together with either frameId or timestamp.
     * @returns {Promise<Object>} An object containing an array of frames is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", timestamp: "2023-01-12T11:20:10.000Z"};
     * let framesMetadata = new mdx.Services.Frames();
     * let frames = await framesMetadata.getFrames(elastic,input);
     */async getFrames(e,t){const r={type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},frameId:{type:["string","null"],default:null,minLength:1,errorMessage:{minLength:"frameId should have atleast 1 character."}},timestamp:{type:["string","null"],default:null},fromTimestamp:{type:["string","null"],default:null},toTimestamp:{type:["string","null"],default:null},maxResultSize:{type:"integer",minimum:1,maximum:Frames.#t,default:Frames.#e,errorMessage:{type:"maxResultSize is not an integer.",minimum:"maxResultSize can have a minimum value of 1.",maximum:`maxResultSize can have a maximum value of ${Frames.#t}.`}}},required:["sensorId"],oneOf:[{required:["fromTimestamp","toTimestamp"]},{required:["timestamp"]},{required:["frameId"]}],not:{anyOf:[{required:["timestamp","maxResultSize"]},{required:["frameId","maxResultSize"]}]},errorMessage:{required:"Input should have required property 'sensorId'.",oneOf:"Input can either have 'frameId', 'timestamp' or a time range i.e. 'fromTimestamp' and 'toTimestamp'.",not:"Input cannot have 'maxResultSize' when it has either 'frameId' or 'timestamp'."}};let a=Validator.validateJsonSchema(t,r);if(!a.valid)throw new BadRequestError(a.reason);if(!Number.isFinite(t.maxResultSize))throw new InvalidInputError("maxResultSize is not a finite integer.");if(null!=t.timestamp||null!=t.frameId){if(t.maxResultSize=1,null!=t.timestamp&&!Validator.isValidISOTimestamp(t.timestamp))throw new InvalidInputError("Invalid timestamp.")}else{let e=Validator.isValidTimeRange(t.fromTimestamp,t.toTimestamp);if(!e.valid)throw new InvalidInputError(e.reason)}t.type="raw";let s=new Array;if("Elasticsearch"===e.getName()){let r=await this.#d(e,t);return r.indexAbsent||(s=Elasticsearch.searchResultFormatter(r.body)),{frames:s}}throw new InternalServerError(`Invalid database: ${e.getName()}.`)}
/** 
     * returns an object containing an array of enhanced frames.
     * @public
     * @async
     * @param {Database} documentDb - Database Object
     * @param {Object} input - Input object.
     * @param {string} input.sensorId
     * @param {string} [input.frameId] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present. frameId can't occur together with maxResultSize.
     * @param {string} [input.timestamp] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present. timestamp can't occur together with maxResultSize.
     * @param {string} [input.fromTimestamp] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present.
     * @param {string} [input.toTimestamp] - Either frameId or timestamp or (fromTimestamp and toTimestamp) should be present.
     * @param {number} [input.maxResultSize=25] - maxResultSize must be an integer. maxResultSize can't occur together with either frameId or timestamp.
     * @returns {Promise<Object>} An object containing an array of enhanced frames is returned
     * @example
     * const mdx = require("@nvidia-mdx/web-api-core");
     * const elastic = new mdx.Utils.Elasticsearch({node: "elasticsearch-url"},databaseConfigMap);
     * let input = {sensorId: "abc", timestamp: "2023-01-12T11:20:10.000Z"};
     * let framesMetadata = new mdx.Services.Frames();
     * let enhancedFrames = await framesMetadata.getEnhancedFrames(elastic,input);
     */async getEnhancedFrames(e,t){const r={type:"object",additionalProperties:{not:!0,errorMessage:"Invalid additional Input ${0#}."},properties:{sensorId:{type:"string",minLength:1,errorMessage:{minLength:"sensorId should have atleast 1 character."}},frameId:{type:["string","null"],default:null,minLength:1,errorMessage:{minLength:"frameId should have atleast 1 character."}},timestamp:{type:["string","null"],default:null},fromTimestamp:{type:["string","null"],default:null},toTimestamp:{type:["string","null"],default:null},maxResultSize:{type:"integer",minimum:1,maximum:Frames.#t,default:Frames.#e,errorMessage:{type:"maxResultSize is not an integer.",minimum:"maxResultSize can have a minimum value of 1.",maximum:`maxResultSize can have a maximum value of ${Frames.#t}.`}}},required:["sensorId"],oneOf:[{required:["fromTimestamp","toTimestamp"]},{required:["timestamp"]},{required:["frameId"]}],not:{anyOf:[{required:["timestamp","maxResultSize"]},{required:["frameId","maxResultSize"]}]},errorMessage:{required:"Input should have required property 'sensorId'.",oneOf:"Input can either have 'frameId', 'timestamp' or a time range i.e. 'fromTimestamp' and 'toTimestamp'.",not:"Input cannot have 'maxResultSize' when it has either 'frameId' or 'timestamp'."}};let a=Validator.validateJsonSchema(t,r);if(!a.valid)throw new BadRequestError(a.reason);if(!Number.isFinite(t.maxResultSize))throw new InvalidInputError("maxResultSize is not a finite integer.");if(null!=t.timestamp||null!=t.frameId){if(t.maxResultSize=1,null!=t.timestamp&&!Validator.isValidISOTimestamp(t.timestamp))throw new InvalidInputError("Invalid timestamp.")}else{let e=Validator.isValidTimeRange(t.fromTimestamp,t.toTimestamp);if(!e.valid)throw new InvalidInputError(e.reason)}t.type="enhanced";let s=new Array;if("Elasticsearch"===e.getName()){let r=await this.#d(e,t);return r.indexAbsent||(s=Elasticsearch.searchResultFormatter(r.body)),{enhancedFrames:s}}throw new InternalServerError(`Invalid database: ${e.getName()}.`)}}module.exports=Frames;