UNPKG

ravendb

Version:
348 lines (346 loc) 16.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QueryOperation = void 0; const Stopwatch_js_1 = require("../../../Utility/Stopwatch.js"); const LogUtil_js_1 = require("../../../Utility/LogUtil.js"); const QueryCommand_js_1 = require("../../Commands/QueryCommand.js"); const index_js_1 = require("../../../Exceptions/index.js"); const Constants_js_1 = require("../../../Constants.js"); const TypeUtil_js_1 = require("../../../Utility/TypeUtil.js"); const DocumentQuery_js_1 = require("../DocumentQuery.js"); const TimeSeriesAggregationResult_js_1 = require("../../Queries/TimeSeries/TimeSeriesAggregationResult.js"); const TimeSeriesRawResult_js_1 = require("../../Queries/TimeSeries/TimeSeriesRawResult.js"); const TimeSeriesRangeAggregation_js_1 = require("../../Queries/TimeSeries/TimeSeriesRangeAggregation.js"); const ObjectUtil_js_1 = require("../../../Utility/ObjectUtil.js"); const TimeSeriesEntry_js_1 = require("../TimeSeries/TimeSeriesEntry.js"); const StringBuilder_js_1 = require("../../../Utility/StringBuilder.js"); const DateUtil_js_1 = require("../../../Utility/DateUtil.js"); const log = (0, LogUtil_js_1.getLogger)({ module: "QueryOperation" }); const facetResultFields = ["Name", "Values", "RemainingHits", "RemainingTermsCount", "RemainingTerms"]; // noinspection ExceptionCaughtLocallyJS class QueryOperation { _session; _indexName; _indexQuery; _metadataOnly; _indexEntriesOnly; _isProjectInto; _currentQueryResults; _fieldsToFetch; _sp; _noTracking; 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; } createRequest() { this._session.incrementRequestCount(); this.logQuery(); return new QueryCommand_js_1.QueryCommand(this._session, this._indexQuery, { metadataOnly: this._metadataOnly, indexEntriesOnly: this._indexEntriesOnly }); } getCurrentQueryResults() { return this._currentQueryResults; } setResult(queryResult) { this.ensureIsAcceptableAndSaveResult(queryResult, null); } _startTiming() { this._sp = Stopwatch_js_1.Stopwatch.createStarted(); } logQuery() { log.info("Executing query '" + this._indexQuery.query + "'" + (this._indexName ? "' on index '" + this._indexName + "'" : "") + " in " + this._session.storeIdentifier); } /* TDB 4.1 public enterQueryContext(): IDisposable { this._startTiming(); if (!this._indexQuery.waitForNonStaleResults) { return null; } return this._session.documentStore.disableAggressiveCaching(this._session.databaseName); } */ 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_js_1.CONSTANTS.Documents.Metadata.KEY}.${Constants_js_1.CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES}`]) { document[Constants_js_1.CONSTANTS.Documents.Metadata.KEY][Constants_js_1.CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES] = document[`${Constants_js_1.CONSTANTS.Documents.Metadata.KEY}.${Constants_js_1.CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES}`]; } const metadata = document[Constants_js_1.CONSTANTS.Documents.Metadata.KEY]; try { const idNode = metadata[Constants_js_1.CONSTANTS.Documents.Metadata.ID]; let id = null; if (idNode && TypeUtil_js_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, index_js_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, index_js_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) { const clusterSession = this._session.clusterSession; clusterSession.registerCompareExchangeIncludes(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 projection = metadata["@projection"]; if (TypeUtil_js_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_js_1.TimeSeriesAggregationResult || clazz === TimeSeriesRawResult_js_1.TimeSeriesRawResult) && (fieldsToFetch.projections.length === 1 || (fieldsToFetch.projections.includes(DocumentQuery_js_1.NESTED_OBJECT_TYPES_PROJECTION_FIELD) && fieldsToFetch.projections.length === 2)); // return primitives only if type was not passed at all AND fields count is 1 // if type was passed then use that even if it's only 1 field if (singleField) { // we only select a single field let projectionField = fieldsToFetch.projections.find(x => x !== DocumentQuery_js_1.NESTED_OBJECT_TYPES_PROJECTION_FIELD); if (fieldsToFetch.sourceAlias) { if (projectionField.startsWith(fieldsToFetch.sourceAlias)) { // remove source-alias from projection name projectionField = projectionField.substring(fieldsToFetch.sourceAlias.length + 1); } if (projectionField.startsWith("'")) { projectionField = projectionField.substring(1, projectionField.length - 1); } } if (conventions.serverToLocalFieldNameConverter) { projectionField = conventions.serverToLocalFieldNameConverter(projectionField); } const jsonNode = document[projectionField]; if (TypeUtil_js_1.TypeUtil.isNullOrUndefined(jsonNode)) { return null; } if (TypeUtil_js_1.TypeUtil.isPrimitive(jsonNode)) { return jsonNode || null; } const isTimeSeriesField = fieldsToFetch.projections[0].startsWith(Constants_js_1.TIME_SERIES.QUERY_FUNCTION); if (!isProjectInto || isTimeSeriesField) { if (isTimeSeriesField || fieldsToFetch.fieldsToFetch[0] === fieldsToFetch.projections[0]) { if (TypeUtil_js_1.TypeUtil.isObject(jsonNode)) { // extraction from original type 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_js_1.TimeSeriesAggregationResult) { Object.assign(result, QueryOperation._reviveTimeSeriesAggregationResult(raw)); } else if (result instanceof TimeSeriesRawResult_js_1.TimeSeriesRawResult) { Object.assign(result, QueryOperation._reviveTimeSeriesRawResult(raw)); } else { if (fieldsToFetch && fieldsToFetch.projections && fieldsToFetch.projections.length) { const keys = conventions.serverToLocalFieldNameConverter ? fieldsToFetch.projections.map(x => conventions.serverToLocalFieldNameConverter(x)) : fieldsToFetch.projections; const nestedTypes = raw[DocumentQuery_js_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 { if (conventions.serverToLocalFieldNameConverter) { const options = { recursive: true, arrayRecursive: true, ignorePaths: [ Constants_js_1.CONSTANTS.Documents.Metadata.IGNORE_CASE_TRANSFORM_REGEX, /@projection/ ], defaultTransform: conventions.serverToLocalFieldNameConverter }; Object.assign(result, ObjectUtil_js_1.ObjectUtil.transformObjectKeys(raw, options)); } else { Object.assign(result, 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_js_1.TimeSeriesAggregationResult) { Object.assign(newValue, QueryOperation._reviveTimeSeriesAggregationResult(value)); } else if (newValue instanceof TimeSeriesRawResult_js_1.TimeSeriesRawResult) { Object.assign(newValue, QueryOperation._reviveTimeSeriesRawResult(value)); } result[timeSeriesField] = newValue; } } } session.onAfterConversionToEntityInvoke(id, document, result); return result; } static _detectTimeSeriesResultType(raw) { const results = raw.Results || []; // duck typing if (results.length && results[0].From && results[0].To) { return new TimeSeriesAggregationResult_js_1.TimeSeriesAggregationResult(); } return new TimeSeriesRawResult_js_1.TimeSeriesRawResult(); } static _reviveTimeSeriesAggregationResult(raw) { const rawLower = ObjectUtil_js_1.ObjectUtil.transformObjectKeys(raw, { defaultTransform: ObjectUtil_js_1.ObjectUtil.camel }); const { results, ...otherProps } = rawLower; const mappedResults = results.map(r => { const { from, to, ...otherRangeProps } = r; const overrides = { from: DateUtil_js_1.DateUtil.utc.parse(from), to: DateUtil_js_1.DateUtil.utc.parse(to) }; return Object.assign(new TimeSeriesRangeAggregation_js_1.TimeSeriesRangeAggregation(), otherRangeProps, overrides); }); return { ...otherProps, results: mappedResults }; } static _reviveTimeSeriesRawResult(raw) { const rawLower = ObjectUtil_js_1.ObjectUtil.transformObjectKeys(raw, { defaultTransform: ObjectUtil_js_1.ObjectUtil.camel }); const { results, ...otherProps } = rawLower; const mappedResults = results.map(r => { const { timestamp, ...otherRangeProps } = r; const overrides = { timestamp: DateUtil_js_1.DateUtil.utc.parse(timestamp), }; return Object.assign(new TimeSeriesEntry_js_1.TimeSeriesEntry(), otherRangeProps, overrides); }); return { ...otherProps, results: mappedResults }; } get noTracking() { return this._noTracking; } set noTracking(value) { this._noTracking = value; } ensureIsAcceptableAndSaveResult(result, duration) { if (TypeUtil_js_1.TypeUtil.isNullOrUndefined(duration)) { if (this._sp) { duration = this._sp.elapsed; } else { duration = null; } } if (!result) { (0, index_js_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; // logging const isStale = result.isStale ? " stale " : " "; const parameters = new StringBuilder_js_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 + ")"); // end logging } static ensureIsAcceptable(result, waitForNonStaleResults, duration, session) { if (duration instanceof Stopwatch_js_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, index_js_1.throwError)("TimeoutException", msg); } } get indexQuery() { return this._indexQuery; } } exports.QueryOperation = QueryOperation; //# sourceMappingURL=QueryOperation.js.map