flexmonster-mongo-connector
Version:
Custom data source API implementation for MongoDB
149 lines (126 loc) • 7.45 kB
text/typescript
import { QueryBuilder } from "../query/builder/QueryBuilder";
import { MongoQueryExecutor } from "../query/MongoQueryExecutor";
import { LocalDataCache } from "./impl/LocalDataCache";
import { IApiRequest } from "../requests/apiRequests/IApiRequest";
import { IDataCache } from "./IDataCache";
import { Register } from "../requests/register/Register";
import { ICacheStrategie } from "./cacheStrategies/ICacheStrategie";
import { ProbibalisticCacheStrategie } from "./cacheStrategies/impl/ProbibalisticCacheStrategie";
import { SimpleCacheStrategie } from "./cacheStrategies/impl/SimpleCacheStrategie";
import { DataRetrievalInterface, RetrievalResult } from "./dataObject/DataRetrievalInterface";
import { PagingInterface} from "../api/IDataAPI";
import { RequestKey } from "../requests/register/RequestKey";
import { ConfigManager } from "../config/ConfigManager";
import { ConfigInterface } from "../config/ConfigInterface";
import { AbstractDataObject } from "./dataObject/impl/AbstractDataObject";
import { LoggingMessages } from "../utils/consts/LoggingMessages";
import { LoggingManager } from "../logging/LoggingManager";
import { IRequestArgument } from "../requests/apiRequests/IRequestArgument";
import { RequestFactory } from "../requests/requestsFactory.ts/RequestsFactory";
import { ArrayDataObject } from "./dataObject/impl/ArrayDataObject";
import { SimpleNumericIterator } from "./customIterators/SimpleNumericIterator";
import { HashGenerator } from "../utils/HashGenerator";
//import { CachedDataInterface } from "./dataObject/CachedDataInterface";
//import { AbstractDataObject } from "./dataObject/impl/AbstractDataObject";
export class DataManager {
private _queryBuilder: QueryBuilder;
private _queryExecutor: MongoQueryExecutor;
private _cacheManager: IDataCache<CacheKeyInterface, any>;
private isProbabilisticCacheFlushEnabled: boolean = true;
private _requestsRegister: Register<string, DataIterationInterface>;
//private readonly CHUNK_SIZE: number = 50000;
constructor(queryBuilder: QueryBuilder, queryExecutor: MongoQueryExecutor) {
this._queryBuilder = queryBuilder;
this._queryExecutor = queryExecutor;
const cacheStategie: ICacheStrategie = this.isProbabilisticCacheFlushEnabled
? new ProbibalisticCacheStrategie() : new SimpleCacheStrategie();
const currentConfig: ConfigInterface = ConfigManager.getInstance().currentConfig;
this._cacheManager = currentConfig.cacheEnabled ? new LocalDataCache(cacheStategie, ConfigManager.getInstance().currentConfig) : null;
this._requestsRegister = new Register();
}
public async getData(requestArgument: IRequestArgument, requestType: string, currentPage: PagingInterface): Promise<any> {
if (currentPage.pageToken != null) {
const registerItem = this._requestsRegister.deleteItem(currentPage.pageToken);
if (registerItem == undefined) throw new Error("The data has been updated. Please refresh the page.");
const retrievalResult: RetrievalResult = await this.getDataChunk(registerItem.data, registerItem.iterator); //registerItem.data.getChunk(registerItem.iterator);
let nextPageToken: string = null;
if (!retrievalResult.isFinished) {
nextPageToken = new RequestKey(registerItem.apiRequest.requestArgument.clientQuery).hash();
this._requestsRegister.addItem(nextPageToken, registerItem)
}
return registerItem.apiRequest.toJSON(retrievalResult.data, nextPageToken);
}
const apiRequest: IApiRequest = RequestFactory.createRequestInstance(requestArgument, requestType);
const dataInstance: AbstractDataObject = await this._getData(apiRequest);
const iterator: Iterator<any> = this.getIterator(dataInstance);//dataInstance.getIterationKeys();
const retrievalResult: RetrievalResult = await this.getDataChunk(dataInstance, iterator); //await data.getChunk(iterator);
let nextPageToken: string = null;
if (!retrievalResult.isFinished) {
nextPageToken = new RequestKey(apiRequest.requestArgument.clientQuery).hash();
this._requestsRegister.addItem(nextPageToken, {
data: dataInstance,
iterator: iterator,
apiRequest: apiRequest
});
}
return apiRequest.toJSON(retrievalResult.data, nextPageToken);
}
private async _getData(apiRequest: IApiRequest): Promise<AbstractDataObject> {
const cacheKey: CacheKeyInterface = {
databaseName: apiRequest.requestArgument.db.databaseName,
index: apiRequest.requestArgument.index,
clientQuery: apiRequest.requestArgument.clientQuery
};
let data: AbstractDataObject = this.getDataFromCache(cacheKey);
LoggingManager.log(`Client query: ${JSON.stringify(apiRequest.requestArgument.clientQuery)}`);
if (data === undefined) {
data = await apiRequest.getData(this._queryBuilder, this._queryExecutor);
this.setDataToCache(cacheKey, <AbstractDataObject>data);
if (ConfigManager.getInstance().currentConfig.cacheEnabled) {
LoggingManager.log(`Putting ${apiRequest.loggingTemplate} data to cache`);
LoggingManager.log(this.getCacheMemoryStatus());
}
} else {
LoggingManager.log(`Getting ${apiRequest.loggingTemplate} data from cache`);
}
return data;
}
private getDataFromCache(keyObject: CacheKeyInterface): AbstractDataObject {
if (this._cacheManager === null) return undefined;
return this._cacheManager.getCache(keyObject);
}
private setDataToCache(keyObject: CacheKeyInterface, data: AbstractDataObject): void {
if (this._cacheManager === null) return undefined;
this._cacheManager.setCache(keyObject, data);
}
private getCacheMemoryStatus(): string {
if (this._cacheManager === null) return LoggingMessages.DISABLED_CACHE_MESSAGE;
return this._cacheManager.getCacheMemoryStatus();
}
private getIterator(dataInstance: AbstractDataObject): Iterator<any> {
if (dataInstance instanceof ArrayDataObject) {
return dataInstance.isCompleted ? dataInstance.getIterationKeys() : new SimpleNumericIterator();
}
return dataInstance.getIterationKeys();
}
private async getDataChunk(dataInstance: DataRetrievalInterface, iterator: Iterator<any>): Promise<RetrievalResult> {
if (dataInstance instanceof ArrayDataObject) {
return dataInstance.isCompleted ? dataInstance.getChunk(iterator) : dataInstance.getChunkAsync(iterator);
}
return dataInstance.getChunk(iterator);
}
// private getCacheKey(objectKey: CacheKeyInterface): string {
// if (objectKey == null) throw new Error("Null cache object key exception");
// return HashGenerator.createHashFromObject(objectKey);
// }
}
export interface CacheKeyInterface {
clientQuery: object,
databaseName: string,
index: string
}
export interface DataIterationInterface {
data: DataRetrievalInterface;
iterator: Iterator<any>;
apiRequest?: IApiRequest;
}