Files
advanced-camera-card/src/card-controller/view/query-executor.ts
T

177 lines
5.8 KiB
TypeScript

import { CapabilitySearchOptions, MediaQuery } from '../../camera-manager/types';
import { MEDIA_CHUNK_SIZE_DEFAULT } from '../../const';
import { ClipsOrSnapshotsOrAll } from '../../types';
import { findBestMediaTimeIndex } from '../../utils/find-best-media-time-index';
import { ViewItem } from '../../view/item';
import {
EventMediaQuery,
FolderViewQuery,
MediaQueries,
Query,
RecordingMediaQuery,
} from '../../view/query';
import { QueryClassifier } from '../../view/query-classifier';
import { QueryResults } from '../../view/query-results';
import { CardViewAPI } from '../types';
import { QueryExecutorOptions, QueryExecutorResult } from './types';
export class QueryExecutor {
protected _api: CardViewAPI;
constructor(api: CardViewAPI) {
this._api = api;
}
public async executeDefaultEventQuery(options?: {
cameraID?: string;
eventsMediaType?: ClipsOrSnapshotsOrAll;
executorOptions?: QueryExecutorOptions;
}): Promise<QueryExecutorResult | null> {
const capabilitySearch: CapabilitySearchOptions =
!options?.eventsMediaType || options?.eventsMediaType === 'all'
? {
anyCapabilities: ['clips', 'snapshots'],
}
: options.eventsMediaType;
const cameraManager = this._api.getCameraManager();
const cameraIDs = options?.cameraID
? cameraManager
.getStore()
.getAllDependentCameras(options.cameraID, capabilitySearch)
: cameraManager.getStore().getCameraIDsWithCapability(capabilitySearch);
if (!cameraIDs.size) {
return null;
}
const rawQueries = cameraManager.generateDefaultEventQueries(cameraIDs, {
limit: this._getChunkLimit(),
...(options?.eventsMediaType === 'clips' && { hasClip: true }),
...(options?.eventsMediaType === 'snapshots' && { hasSnapshot: true }),
});
if (!rawQueries) {
return null;
}
const queries = new EventMediaQuery(rawQueries);
return await this.executeMediaQuery(queries, options?.executorOptions);
}
public async executeDefaultRecordingQuery(options?: {
cameraID?: string;
executorOptions?: QueryExecutorOptions;
}): Promise<QueryExecutorResult | null> {
const cameraManager = this._api.getCameraManager();
const cameraIDs = options?.cameraID
? cameraManager.getStore().getAllDependentCameras(options.cameraID, 'recordings')
: cameraManager.getStore().getCameraIDsWithCapability('recordings');
if (!cameraIDs.size) {
return null;
}
const rawQueries = cameraManager.generateDefaultRecordingQueries(cameraIDs, {
limit: this._getChunkLimit(),
});
if (!rawQueries) {
return null;
}
const queries = new RecordingMediaQuery(rawQueries);
return await this.executeMediaQuery(queries, options?.executorOptions);
}
public async executeQuery(
query: Query,
executorOptions?: QueryExecutorOptions,
): Promise<QueryExecutorResult | null> {
/* istanbul ignore else: this path cannot be reached -- @preserve */
if (QueryClassifier.isMediaQuery(query)) {
return await this.executeMediaQuery(query, executorOptions);
} else if (QueryClassifier.isFolderQuery(query)) {
return await this._executeFolderQuery(query, executorOptions);
}
/* istanbul ignore next: this path cannot be reached -- @preserve */
return null;
}
public async executeMediaQuery(
query: MediaQueries,
executorOptions?: QueryExecutorOptions,
): Promise<QueryExecutorResult | null> {
const queries = query.getQuery();
if (!queries) {
return null;
}
const mediaArray = await this._api
.getCameraManager()
.executeMediaQueries<MediaQuery>(queries, {
useCache: executorOptions?.useCache,
});
const queryResults = mediaArray
? this._generateQueriesResults(mediaArray, executorOptions)
: null;
return queryResults ? { query, queryResults } : null;
}
private _generateQueriesResults(
itemArray: ViewItem[],
executorOptions?: QueryExecutorOptions,
): QueryResults | null {
const queryResults = new QueryResults({ results: itemArray });
if (executorOptions?.rejectResults?.(queryResults)) {
return null;
}
if (executorOptions?.selectResult?.id) {
queryResults.selectBestResult((media) =>
media.findIndex((m) => m.getID() === executorOptions.selectResult?.id),
);
} else if (executorOptions?.selectResult?.func) {
queryResults.selectResultIfFound(executorOptions.selectResult.func);
} else if (executorOptions?.selectResult?.time) {
queryResults.selectBestResult((itemArray) =>
findBestMediaTimeIndex(
itemArray,
executorOptions.selectResult?.time?.time as Date,
executorOptions.selectResult?.time?.favorCameraID,
),
);
}
return queryResults;
}
public async executeDefaultFolderQuery(
executorOptions?: QueryExecutorOptions,
): Promise<QueryExecutorResult | null> {
const query = this._api.getFoldersManager().generateDefaultFolderQuery();
return query
? this._executeFolderQuery(new FolderViewQuery(query), executorOptions)
: null;
}
private async _executeFolderQuery(
query: FolderViewQuery,
executorOptions?: QueryExecutorOptions,
): Promise<QueryExecutorResult | null> {
const rawQuery = query.getQuery();
if (!rawQuery) {
return null;
}
const itemArray = await this._api
.getFoldersManager()
.expandFolder(rawQuery, { useCache: executorOptions?.useCache });
const queryResults = itemArray
? this._generateQueriesResults(itemArray, executorOptions)
: null;
return queryResults ? { query, queryResults } : null;
}
protected _getChunkLimit(): number {
const cardWideConfig = this._api.getConfigManager().getCardWideConfig();
return (
cardWideConfig?.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT
);
}
}