UNPKG

@configurator/ravendb

Version:
318 lines 15.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QueryOperation = void 0; const Stopwatch_1 = require("../../../Utility/Stopwatch"); const LogUtil_1 = require("../../../Utility/LogUtil"); const QueryCommand_1 = require("../../Commands/QueryCommand"); const Exceptions_1 = require("../../../Exceptions"); const Constants_1 = require("../../../Constants"); const TypeUtil_1 = require("../../../Utility/TypeUtil"); const StringUtil_1 = require("../../../Utility/StringUtil"); const DocumentQuery_1 = require("../DocumentQuery"); const TimeSeriesAggregationResult_1 = require("../../Queries/TimeSeries/TimeSeriesAggregationResult"); const TimeSeriesRawResult_1 = require("../../Queries/TimeSeries/TimeSeriesRawResult"); const TimeSeriesRangeAggregation_1 = require("../../Queries/TimeSeries/TimeSeriesRangeAggregation"); const ObjectUtil_1 = require("../../../Utility/ObjectUtil"); const TimeSeriesEntry_1 = require("../TimeSeries/TimeSeriesEntry"); const StringBuilder_1 = require("../../../Utility/StringBuilder"); const log = (0, LogUtil_1.getLogger)({ module: "QueryOperation" }); const facetResultFields = ["Name", "Values", "RemainingHits", "RemainingTermsCount", "RemainingTerms"]; class QueryOperation { constructor(session, indexName, indexQuery, fieldsToFetch, disableEntitiesTracking, metadataOnly, indexEntriesOnly, isProjectInto) { this._session = session; this._indexName = indexName; this._indexQuery = indexQuery; this._fieldsToFetch = fieldsToFetch; this._noTracking = disableEntitiesTracking; this._metadataOnly = metadataOnly; this._indexEntriesOnly = indexEntriesOnly; this._isProjectInto = isProjectInto; this._assertPageSizeSet(); } createRequest() { this._session.incrementRequestCount(); this.logQuery(); return new QueryCommand_1.QueryCommand(this._session, this._indexQuery, { metadataOnly: this._metadataOnly, indexEntriesOnly: this._indexEntriesOnly }); } getCurrentQueryResults() { return this._currentQueryResults; } setResult(queryResult) { this.ensureIsAcceptableAndSaveResult(queryResult, null); } _assertPageSizeSet() { if (!this._session.conventions.isThrowIfQueryPageSizeIsNotSet()) { return; } if (this._indexQuery.pageSizeSet) { return; } (0, Exceptions_1.throwError)("InvalidOperationException", "Attempt to query without explicitly specifying a page size. " + "You can use .take() methods to set maximum number of results. " + "By default the page size is set to Integer.MAX_VALUE and can cause severe performance degradation."); } _startTiming() { this._sp = Stopwatch_1.Stopwatch.createStarted(); } logQuery() { log.info("Executing query '" + this._indexQuery.query + "'" + (this._indexName ? "' on index '" + this._indexName + "'" : "") + " in " + this._session.storeIdentifier); } complete(documentType) { const queryResult = this._currentQueryResults.createSnapshot(); const result = []; this._completeInternal(documentType, queryResult, x => result.push(x)); return result; } _completeInternal(documentType, queryResult, addToResult) { if (!this._noTracking) { this._session.registerIncludes(queryResult.includes); } try { for (const document of queryResult.results) { if (document[`${Constants_1.CONSTANTS.Documents.Metadata.KEY}.${Constants_1.CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES}`]) { document[Constants_1.CONSTANTS.Documents.Metadata.KEY][Constants_1.CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES] = document[`${Constants_1.CONSTANTS.Documents.Metadata.KEY}.${Constants_1.CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES}`]; } const metadata = document[Constants_1.CONSTANTS.Documents.Metadata.KEY]; try { const idNode = metadata[Constants_1.CONSTANTS.Documents.Metadata.ID]; let id = null; if (idNode && TypeUtil_1.TypeUtil.isString(idNode)) { id = idNode; } addToResult(QueryOperation.deserialize(id, document, metadata, this._fieldsToFetch, this._noTracking, this._session, documentType, this._isProjectInto, queryResult.timeSeriesFields || [])); } catch (e) { if (Object.keys(document).length !== facetResultFields.length) { throw e; } for (const prop of facetResultFields) { if (!(prop in document)) { throw e; } } (0, Exceptions_1.throwError)("InvalidArgumentException", "Raw query with aggregation by facet should be called by executeAggregation method."); } } } catch (err) { log.warn(err, "Unable to read query result JSON."); (0, Exceptions_1.throwError)("RavenException", "Unable to read json.", err); } if (!this._noTracking) { this._session.registerMissingIncludes(queryResult.results, queryResult.includes, queryResult.includedPaths); if (queryResult.counterIncludes) { this._session.registerCounters(queryResult.counterIncludes, queryResult.includedCounterNames); } if (queryResult.timeSeriesIncludes) { this._session.registerTimeSeries(queryResult.timeSeriesIncludes); } if (queryResult.compareExchangeValueIncludes) { this._session.clusterSession.registerCompareExchangeValues(queryResult.compareExchangeValueIncludes, false); } if (queryResult.revisionIncludes) { this._session.registerRevisionIncludes(queryResult.revisionIncludes); } } } static deserialize(id, document, metadata, fieldsToFetch, disableEntitiesTracking, session, clazz, isProjectInto, timeSeriesFields) { const { conventions } = session; const { entityFieldNameConvention } = conventions; const projection = metadata["@projection"]; if (TypeUtil_1.TypeUtil.isNullOrUndefined(projection) || projection === false) { const entityType = conventions.getJsTypeByDocumentType(clazz); return session.trackEntity(entityType, id, document, metadata, disableEntitiesTracking); } const singleField = fieldsToFetch && fieldsToFetch.projections && (!clazz || clazz === TimeSeriesAggregationResult_1.TimeSeriesAggregationResult || clazz === TimeSeriesRawResult_1.TimeSeriesRawResult) && (fieldsToFetch.projections.length === 1 || (fieldsToFetch.projections.includes(DocumentQuery_1.NESTED_OBJECT_TYPES_PROJECTION_FIELD) && fieldsToFetch.projections.length === 2)); if (singleField) { let projectionField = fieldsToFetch.projections.find(x => x !== DocumentQuery_1.NESTED_OBJECT_TYPES_PROJECTION_FIELD); if (fieldsToFetch.sourceAlias) { if (projectionField.startsWith(fieldsToFetch.sourceAlias)) { projectionField = projectionField.substring(fieldsToFetch.sourceAlias.length + 1); } if (projectionField.startsWith("'")) { projectionField = projectionField.substring(1, projectionField.length - 1); } } if (entityFieldNameConvention) { projectionField = StringUtil_1.StringUtil.changeCase(entityFieldNameConvention, projectionField); } const jsonNode = document[projectionField]; if (TypeUtil_1.TypeUtil.isNullOrUndefined(jsonNode)) { return null; } if (TypeUtil_1.TypeUtil.isPrimitive(jsonNode)) { return jsonNode || null; } const isTimeSeriesField = fieldsToFetch.projections[0].startsWith(Constants_1.TIME_SERIES.QUERY_FUNCTION); if (!isProjectInto || isTimeSeriesField) { if (isTimeSeriesField || fieldsToFetch.fieldsToFetch[0] === fieldsToFetch.projections[0]) { if (TypeUtil_1.TypeUtil.isObject(jsonNode)) { document = jsonNode; } } } } const projType = conventions.getJsTypeByDocumentType(clazz); const documentRef = { value: document }; session.onBeforeConversionToEntityInvoke(id, clazz, documentRef); document = documentRef.value; const raw = conventions.objectMapper.fromObjectLiteral(document); const result = projType ? new (Function.prototype.bind.apply(projType)) : {}; const mapper = conventions.objectMapper; if (result instanceof TimeSeriesAggregationResult_1.TimeSeriesAggregationResult) { Object.assign(result, QueryOperation._reviveTimeSeriesAggregationResult(raw, conventions)); } else if (result instanceof TimeSeriesRawResult_1.TimeSeriesRawResult) { Object.assign(result, QueryOperation._reviveTimeSeriesRawResult(raw, conventions)); } else { if (fieldsToFetch && fieldsToFetch.projections && fieldsToFetch.projections.length) { const keys = conventions.entityFieldNameConvention ? fieldsToFetch.projections.map(x => StringUtil_1.StringUtil.changeCase(conventions.entityFieldNameConvention, x)) : fieldsToFetch.projections; const nestedTypes = raw[DocumentQuery_1.NESTED_OBJECT_TYPES_PROJECTION_FIELD]; for (let i = 0; i < keys.length; i++) { const key = keys[i]; const mapped = mapper.fromObjectLiteral(raw, { typeName: "object", nestedTypes }); result[key] = mapped[key]; } } else { Object.assign(result, !entityFieldNameConvention ? raw : conventions.transformObjectKeysToLocalFieldNameConvention(raw)); } } if (timeSeriesFields && timeSeriesFields.length) { for (const timeSeriesField of timeSeriesFields) { const value = document[timeSeriesField]; if (value) { const newValue = QueryOperation._detectTimeSeriesResultType(value); if (newValue instanceof TimeSeriesAggregationResult_1.TimeSeriesAggregationResult) { Object.assign(newValue, QueryOperation._reviveTimeSeriesAggregationResult(value, conventions)); } else if (newValue instanceof TimeSeriesRawResult_1.TimeSeriesRawResult) { Object.assign(newValue, QueryOperation._reviveTimeSeriesRawResult(value, conventions)); } result[timeSeriesField] = newValue; } } } session.onAfterConversionToEntityInvoke(id, document, result); return result; } static _detectTimeSeriesResultType(raw) { const results = raw.Results || []; if (results.length && results[0].From && results[0].To) { return new TimeSeriesAggregationResult_1.TimeSeriesAggregationResult(); } return new TimeSeriesRawResult_1.TimeSeriesRawResult(); } static _reviveTimeSeriesAggregationResult(raw, conventions) { const rawLower = ObjectUtil_1.ObjectUtil.transformObjectKeys(raw, { defaultTransform: "camel" }); const { results, ...otherProps } = rawLower; const mappedResults = results.map(r => { const { from, to, ...otherRangeProps } = r; const overrides = { from: conventions.dateUtil.parse(from), to: conventions.dateUtil.parse(to) }; return Object.assign(new TimeSeriesRangeAggregation_1.TimeSeriesRangeAggregation(), otherRangeProps, overrides); }); return { ...otherProps, results: mappedResults }; } static _reviveTimeSeriesRawResult(raw, conventions) { const rawLower = ObjectUtil_1.ObjectUtil.transformObjectKeys(raw, { defaultTransform: "camel" }); const { results, ...otherProps } = rawLower; const mappedResults = results.map(r => { const { timestamp, ...otherRangeProps } = r; const overrides = { timestamp: conventions.dateUtil.parse(timestamp), }; return Object.assign(new TimeSeriesEntry_1.TimeSeriesEntry(), otherRangeProps, overrides); }); return { ...otherProps, results: mappedResults }; } get noTracking() { return this._noTracking; } set noTracking(value) { this._noTracking = value; } ensureIsAcceptableAndSaveResult(result, duration) { if (TypeUtil_1.TypeUtil.isNullOrUndefined(duration)) { if (this._sp) { duration = this._sp.elapsed; } else { duration = null; } } if (!result) { (0, Exceptions_1.throwError)("IndexDoesNotExistException", `Could not find index ${this._indexName}.`); } QueryOperation.ensureIsAcceptable(result, this._indexQuery.waitForNonStaleResults, duration, this._session); this._saveQueryResult(result); } _saveQueryResult(result) { this._currentQueryResults = result; const isStale = result.isStale ? " stale " : " "; const parameters = new StringBuilder_1.StringBuilder(); if (this._indexQuery.queryParameters && this._indexQuery.queryParameters.length) { parameters.append("(parameters: "); let first = true; const queryParameters = this._indexQuery.queryParameters; for (const parameterKey of Object.keys(queryParameters)) { const parameterValue = queryParameters[parameterKey]; if (!first) { parameters.append(", "); } parameters.append(parameterKey) .append(" = ") .append(parameterValue); first = false; } parameters.append(") "); } log.info("Query '" + this._indexQuery.query + "' " + parameters.toString() + "returned " + result.results.length + isStale + "results (total index results: " + result.totalResults + ")"); } static ensureIsAcceptable(result, waitForNonStaleResults, duration, session) { if (duration instanceof Stopwatch_1.Stopwatch) { duration.stop(); return QueryOperation.ensureIsAcceptable(result, waitForNonStaleResults, duration.elapsed, session); } if (waitForNonStaleResults && result.isStale) { const msg = "Waited for " + duration.toString() + " for the query to return non stale result."; (0, Exceptions_1.throwError)("TimeoutException", msg); } } get indexQuery() { return this._indexQuery; } } exports.QueryOperation = QueryOperation; //# sourceMappingURL=QueryOperation.js.map