UNPKG

ravendb

Version:
1,118 lines 82.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AbstractDocumentQuery = void 0; const QueryOperation_js_1 = require("./Operations/QueryOperation.js"); const GroupByCountToken_js_1 = require("./Tokens/GroupByCountToken.js"); const GroupByToken_js_1 = require("./Tokens/GroupByToken.js"); const HighlightingToken_js_1 = require("./Tokens/HighlightingToken.js"); const FieldsToFetchToken_js_1 = require("./Tokens/FieldsToFetchToken.js"); const FromToken_js_1 = require("./Tokens/FromToken.js"); const DistinctToken_js_1 = require("./Tokens/DistinctToken.js"); const QueryStatistics_js_1 = require("./QueryStatistics.js"); const index_js_1 = require("../../Exceptions/index.js"); const IndexQuery_js_1 = require("../Queries/IndexQuery.js"); const GroupBy_js_1 = require("../Queries/GroupBy.js"); const GroupByKeyToken_js_1 = require("../Session/Tokens/GroupByKeyToken.js"); const GroupBySumToken_js_1 = require("../Session/Tokens/GroupBySumToken.js"); const ExplanationToken_js_1 = require("../Session/Tokens/ExplanationToken.js"); const TimingsToken_js_1 = require("../Session/Tokens/TimingsToken.js"); const TrueToken_js_1 = require("../Session/Tokens/TrueToken.js"); const WhereToken_js_1 = require("../Session/Tokens/WhereToken.js"); const QueryFieldUtil_js_1 = require("../Queries/QueryFieldUtil.js"); const CloseSubclauseToken_js_1 = require("./Tokens/CloseSubclauseToken.js"); const OpenSubclauseToken_js_1 = require("./Tokens/OpenSubclauseToken.js"); const NegateToken_js_1 = require("./Tokens/NegateToken.js"); const WhereParams_js_1 = require("./WhereParams.js"); const TypeUtil_js_1 = require("../../Utility/TypeUtil.js"); const DateUtil_js_1 = require("../../Utility/DateUtil.js"); const MethodCall_js_1 = require("./MethodCall.js"); const QueryOperatorToken_js_1 = require("./Tokens/QueryOperatorToken.js"); const OrderByToken_js_1 = require("./Tokens/OrderByToken.js"); const FacetToken_js_1 = require("./Tokens/FacetToken.js"); const CounterIncludesToken_js_1 = require("./Tokens/CounterIncludesToken.js"); const node_events_1 = require("node:events"); const StringUtil_js_1 = require("../../Utility/StringUtil.js"); const IntersectMarkerToken_js_1 = require("./Tokens/IntersectMarkerToken.js"); const DocumentConventions_js_1 = require("../Conventions/DocumentConventions.js"); const Constants_js_1 = require("../../Constants.js"); const DocumentQueryHelper_js_1 = require("./DocumentQueryHelper.js"); const ShapeToken_js_1 = require("./Tokens/ShapeToken.js"); const SessionEvents_js_1 = require("./SessionEvents.js"); const CmpXchg_js_1 = require("./CmpXchg.js"); const DocumentQueryCustomization_js_1 = require("./DocumentQueryCustomization.js"); const MoreLikeThisScope_js_1 = require("../Queries/MoreLikeThis/MoreLikeThisScope.js"); const MoreLikeThisToken_js_1 = require("./Tokens/MoreLikeThisToken.js"); const LazyQueryOperation_js_1 = require("../Session/Operations/Lazy/LazyQueryOperation.js"); const SuggestToken_js_1 = require("./Tokens/SuggestToken.js"); const SuggestionWithTerm_js_1 = require("../Queries/Suggestions/SuggestionWithTerm.js"); const SuggestionWithTerms_js_1 = require("../Queries/Suggestions/SuggestionWithTerms.js"); const QueryData_js_1 = require("../Queries/QueryData.js"); const QueryTimings_js_1 = require("../Queries/Timings/QueryTimings.js"); const Explanations_js_1 = require("../Queries/Explanation/Explanations.js"); const HighlightingOptions_js_1 = require("../Queries/Highlighting/HighlightingOptions.js"); const QueryHighlightings_js_1 = require("../Queries/Highlighting/QueryHighlightings.js"); const IncludesUtil_js_1 = require("./IncludesUtil.js"); const TimeSeriesIncludesToken_js_1 = require("./Tokens/TimeSeriesIncludesToken.js"); const CompareExchangeValueIncludesToken_js_1 = require("./Tokens/CompareExchangeValueIncludesToken.js"); const TimeSeriesQueryBuilder_js_1 = require("../Queries/TimeSeries/TimeSeriesQueryBuilder.js"); const StringBuilder_js_1 = require("../../Utility/StringBuilder.js"); const RevisionIncludesToken_js_1 = require("./Tokens/RevisionIncludesToken.js"); const QueryShardedContextBuilder_js_1 = require("./Querying/Sharding/QueryShardedContextBuilder.js"); const VectorFieldFactory_js_1 = require("./VectorFieldFactory.js"); const VectorEmbeddingFieldFactory_js_1 = require("../Queries/VectorSearch/VectorEmbeddingFieldFactory.js"); const Serializer_js_1 = require("../../Mapping/Json/Serializer.js"); const VectorSearchToken_js_1 = require("./Tokens/VectorSearchToken.js"); /** * A query against a Raven index */ class AbstractDocumentQuery extends node_events_1.EventEmitter { _clazz; _aliasToGroupByFieldName = {}; _defaultOperator = "AND"; _rootTypes = new Set(); /** * Whether to negate the next operation */ _negate; /** * Whether to negate the next operation in Filter */ _negateFilter; _indexName; _collectionName; _currentClauseDepth; _queryRaw; get indexName() { return this._indexName; } get collectionName() { return this._collectionName; } _filterModeStack = []; _queryParameters = {}; _isIntersect; _isGroupBy; _theSession; _pageSize; _selectTokens = []; _fromToken; _declareTokens; _loadTokens; fieldsToFetchToken; _isProjectInto; _whereTokens = []; _groupByTokens = []; _orderByTokens = []; _withTokens = []; _filterTokens = []; _start; _conventions; /** * Limits filter clause. */ _filterLimit; _timeout; _theWaitForNonStaleResults; _documentIncludes = new Set(); _statsCallback = TypeUtil_js_1.TypeUtil.NOOP; /** * Holds the query stats */ _queryStats = new QueryStatistics_js_1.QueryStatistics(); _disableEntitiesTracking; _disableCaching; projectionBehavior; _parameterPrefix = "p"; _includesAlias; _highlightingTokens = []; _queryHighlightings = new QueryHighlightings_js_1.QueryHighlightings(); _queryTimings; _explanations; _explanationToken; isFilterActive() { return this._filterModeStack.length && this._filterModeStack[0]; } get isDistinct() { return this._selectTokens && this._selectTokens.length && this._selectTokens[0] instanceof DistinctToken_js_1.DistinctToken; } get theWaitForNonStaleResults() { return this._theWaitForNonStaleResults; } get timeout() { return this._timeout; } get queryParameters() { return this._queryParameters; } get selectTokens() { return this._selectTokens; } get isProjectInto() { return this._isProjectInto; } set isProjectInto(value) { this._isProjectInto = value; } /** * Gets the document convention from the query session */ get conventions() { return this._conventions; } /** * Gets the session associated with this document query */ get session() { return this._theSession; } isDynamicMapReduce() { return this._groupByTokens && !!this._groupByTokens.length; } _isInMoreLikeThis; _getDefaultTimeout() { return this._conventions.waitForNonStaleResultsTimeout; } constructor(clazz, session, indexName, collectionName, isGroupBy, declareTokens, loadTokens, fromAlias = null, isProjectInto = false) { super(); this._clazz = clazz; this._rootTypes.add(clazz); this._isGroupBy = isGroupBy; this._indexName = indexName; this._collectionName = collectionName; this._fromToken = FromToken_js_1.FromToken.create(indexName, collectionName, fromAlias); this._declareTokens = declareTokens; this._loadTokens = loadTokens; this._theSession = session; this.on("afterQueryExecuted", (result) => { this._updateStatsAndHighlightingsAndExplanations(result); }); this._conventions = !session ? new DocumentConventions_js_1.DocumentConventions() : session.conventions; // TBD _linqPathProvider = new LinqPathProvider(_conventions); this._isProjectInto = isProjectInto || false; } _assertMethodIsCurrentlySupported(methodName) { if (!this.isFilterActive()) { return; } (0, index_js_1.throwError)("InvalidQueryException", methodName + " is currently unsupported for 'filter'. If you want to use" + methodName + " in where method you have to put it before 'filter'"); } _getCurrentWhereTokens() { if (this.isFilterActive()) { return this._filterTokens; } if (!this._isInMoreLikeThis) { return this._whereTokens; } if (!this._whereTokens || !this._whereTokens.length) { (0, index_js_1.throwError)("InvalidOperationException", "Cannot get MoreLikeThisToken because there are no where token specified."); } const lastToken = this._whereTokens.at(-1); if (lastToken instanceof MoreLikeThisToken_js_1.MoreLikeThisToken) { return lastToken.whereTokens; } else { (0, index_js_1.throwError)("InvalidOperationException", "Last token is not MoreLikeThisToken"); } } _ensureValidFieldName(fieldName, isNestedPath) { if (!this._theSession || !this._theSession.conventions || isNestedPath || this._isGroupBy) { return QueryFieldUtil_js_1.QueryFieldUtil.escapeIfNecessary(fieldName, isNestedPath); } for (const rootType of this._rootTypes) { const identityProperty = this._theSession.conventions.getIdentityProperty(rootType); if (identityProperty && identityProperty === fieldName) { return Constants_js_1.CONSTANTS.Documents.Indexing.Fields.DOCUMENT_ID_FIELD_NAME; } } return QueryFieldUtil_js_1.QueryFieldUtil.escapeIfNecessary(fieldName); } _appendOperatorIfNeeded(tokens) { this._assertNoRawQuery(); if (!tokens || !tokens.length) { return; } const lastToken = tokens.at(-1); if (!(lastToken instanceof WhereToken_js_1.WhereToken) && !(lastToken instanceof CloseSubclauseToken_js_1.CloseSubclauseToken)) { return; } let lastWhere = null; for (let i = tokens.length - 1; i >= 0; i--) { if (tokens[i] instanceof WhereToken_js_1.WhereToken) { lastWhere = tokens[i]; break; } } let token = this._defaultOperator === "AND" ? QueryOperatorToken_js_1.QueryOperatorToken.AND : QueryOperatorToken_js_1.QueryOperatorToken.OR; if (lastWhere && lastWhere.options?.searchOperator) { token = QueryOperatorToken_js_1.QueryOperatorToken.OR; // default to OR operator after search if AND was not specified explicitly } tokens.push(token); } _transformCollection(fieldName, values) { const result = []; for (const value of values) { if (Array.isArray(value)) { result.push(...this._transformCollection(fieldName, value)); } else { const nestedWhereParams = new WhereParams_js_1.WhereParams(); nestedWhereParams.allowWildcards = true; nestedWhereParams.fieldName = fieldName; nestedWhereParams.value = value; result.push(this._transformValue(nestedWhereParams)); } } return result; } _negateIfNeeded(tokens, fieldName) { if (!this._negate) { return; } this._negate = false; if (!tokens || !tokens.length || tokens.at(-1) instanceof OpenSubclauseToken_js_1.OpenSubclauseToken) { if (fieldName) { this._whereExists(fieldName); } else { this._whereTrue(); } this._andAlso(); } tokens.push(NegateToken_js_1.NegateToken.INSTANCE); } _usingDefaultOperator(operator) { if (this._getCurrentWhereTokens().length > 0) { (0, index_js_1.throwError)("InvalidOperationException", "Default operator can only be set before any where clause is added."); } this._defaultOperator = operator; } /** * Instruct the query to wait for non stale result for the specified wait timeout. * This shouldn't be used outside of unit tests unless you are well aware of the implications */ _waitForNonStaleResults(waitTimeout) { if (this._theWaitForNonStaleResults) { if (!this._timeout || waitTimeout && this._timeout < waitTimeout) { this._timeout = waitTimeout; } return; } this._theWaitForNonStaleResults = true; this._timeout = waitTimeout || this._getDefaultTimeout(); } _getLazyQueryOperation() { if (!this._queryOperation) { this._queryOperation = this.initializeQueryOperation(); } const clazz = this._conventions.getJsTypeByDocumentType(this._clazz); return new LazyQueryOperation_js_1.LazyQueryOperation(this._theSession, this._queryOperation, this, clazz); } initializeQueryOperation() { const beforeQueryEventArgs = new SessionEvents_js_1.SessionBeforeQueryEventArgs(this._theSession, new DocumentQueryCustomization_js_1.DocumentQueryCustomization(this)); this._theSession.emit("beforeQuery", beforeQueryEventArgs); const indexQuery = this.getIndexQuery(); return new QueryOperation_js_1.QueryOperation(this._theSession, this._indexName, indexQuery, this.fieldsToFetchToken, this._disableEntitiesTracking, false, false, this._isProjectInto); } _transformValue(whereParams, forRange = false) { if (TypeUtil_js_1.TypeUtil.isNullOrUndefined(whereParams.value)) { return null; } if ("" === whereParams.value) { return ""; } let objectValue = null; if (this._conventions.tryConvertValueToObjectForQuery(whereParams.fieldName, whereParams.value, forRange, s => objectValue = s)) { return objectValue; } const value = whereParams.value; return this._stringifyParameter(value); } _stringifyParameter(value) { if (TypeUtil_js_1.TypeUtil.isDate(value)) { return DateUtil_js_1.DateUtil.utc.stringify(value); } if (TypeUtil_js_1.TypeUtil.isString(value)) { return value; } if (TypeUtil_js_1.TypeUtil.isNumber(value)) { return value; } if (value === false || value === true) { return value; } return value || null; } _addQueryParameter(value) { const parameterName = this.parameterPrefix + Object.keys(this._queryParameters).length; this._queryParameters[parameterName] = this._stringifyParameter(value); return parameterName; } static _getSourceAliasIfExists(documentType, queryData, fields, sourceAlias) { sourceAlias(null); if (fields.length !== 1 || !fields[0]) { return; } const indexOf = fields[0].indexOf("."); if (indexOf === -1) { return; } const possibleAlias = fields[0].substring(0, indexOf); if (queryData.fromAlias && queryData.fromAlias === possibleAlias) { sourceAlias(possibleAlias); return; } if (!queryData.loadTokens || queryData.loadTokens.length === 0) { return; } if (!queryData.loadTokens.some(x => x.alias === possibleAlias)) { return; } sourceAlias(possibleAlias); } _createTimeSeriesQueryData(timeSeriesQuery) { const builder = new TimeSeriesQueryBuilder_js_1.TimeSeriesQueryBuilder(); timeSeriesQuery(builder); const fields = [Constants_js_1.TIME_SERIES.SELECT_FIELD_NAME + "(" + builder.queryText + ")"]; const projections = [Constants_js_1.TIME_SERIES.QUERY_FUNCTION]; return new QueryData_js_1.QueryData(fields, projections); } _addFilterLimit(filterLimit) { if (filterLimit <= 0) { (0, index_js_1.throwError)("InvalidOperationException", "filterLimit need to be positive and bigger than 0."); } if (filterLimit !== Number.MAX_SAFE_INTEGER) { this._filterLimit = filterLimit; } } _getCurrentOrderByTokens() { return this._orderByTokens; } _getCurrentFilterTokens() { return this._filterTokens; } _updateFieldsToFetchToken(fieldsToFetch) { this.fieldsToFetchToken = fieldsToFetch; if (this._selectTokens && !this._selectTokens.length) { this._selectTokens.push(fieldsToFetch); } else { const fetchToken = [...this._selectTokens] .find(x => x instanceof FieldsToFetchToken_js_1.FieldsToFetchToken); if (fetchToken) { const idx = this._selectTokens.indexOf(fetchToken); this._selectTokens[idx] = fieldsToFetch; } else { this._selectTokens.push(fieldsToFetch); } } } getIndexQuery() { let serverVersion = null; if (this._theSession && this._theSession.requestExecutor) { serverVersion = this._theSession.requestExecutor.lastServerVersion; } const compatibilityMode = serverVersion && serverVersion.localeCompare("4.2") < 0; const query = this.toString(compatibilityMode); const indexQuery = this._generateIndexQuery(query); this.emit("beforeQueryExecuted", indexQuery); return indexQuery; } /** * Gets the fields for projection */ getProjectionFields() { return this.fieldsToFetchToken && this.fieldsToFetchToken.projections ? [...this.fieldsToFetchToken.projections] : []; } /** * Order the search results randomly using the specified seed * this is useful if you want to have repeatable random queries */ _randomOrdering(seed) { this._assertNoRawQuery(); this._noCaching(); if (!seed) { this._orderByTokens.push(OrderByToken_js_1.OrderByToken.random); return; } this._orderByTokens.push(OrderByToken_js_1.OrderByToken.createRandom(seed)); } // TBD public void _customSortUsing(String typeName) // TBD public void _customSortUsing(String typeName, boolean descending) _projection(projectionBehavior) { this.projectionBehavior = projectionBehavior; } _shardContext(action) { const builderImpl = new QueryShardedContextBuilder_js_1.QueryShardedContextBuilder(); action(builderImpl); const shardContext = builderImpl.documentIds.size === 1 ? Array.from(builderImpl.documentIds.keys())[0] : Array.from(builderImpl.documentIds); this.queryParameters[Constants_js_1.CONSTANTS.Documents.Querying.SHARD_CONTEXT_PARAMETER_NAME] = shardContext; } addGroupByAlias(fieldName, projectedName) { this._aliasToGroupByFieldName[projectedName] = fieldName; } _assertNoRawQuery() { if (this._queryRaw) { (0, index_js_1.throwError)("InvalidOperationException", "RawQuery was called, cannot modify this query by calling on " + "operations that would modify the query (such as Where, Select, OrderBy, GroupBy, etc)"); } } addParameter(name, value) { name = name.replace(/^\$/, ""); if (Object.keys(this._queryParameters).includes(name)) { (0, index_js_1.throwError)("InvalidOperationException", "The parameter " + name + " was already added"); } this._queryParameters[name] = value; } _groupBy(fieldOrFieldName, ...fieldsOrFieldNames) { if (typeof (fieldOrFieldName) === "string") { const mapping = fieldsOrFieldNames.map(x => GroupBy_js_1.GroupBy.field(x)); this._groupBy(GroupBy_js_1.GroupBy.field(fieldOrFieldName), ...mapping); return; } if (!this._fromToken.isDynamic) { (0, index_js_1.throwError)("InvalidOperationException", "groupBy only works with dynamic queries"); } this._assertNoRawQuery(); this._isGroupBy = true; const fieldName = this._ensureValidFieldName(fieldOrFieldName.field, false); this._groupByTokens.push(GroupByToken_js_1.GroupByToken.create(fieldName, fieldOrFieldName.method)); if (!fieldsOrFieldNames || !fieldsOrFieldNames.length) { return; } for (const item of fieldsOrFieldNames) { fieldOrFieldName = this._ensureValidFieldName(item.field, false); this._groupByTokens.push(GroupByToken_js_1.GroupByToken.create(fieldOrFieldName, item.method)); } } _groupByKey(fieldName, projectedName = null) { this._assertNoRawQuery(); this._isGroupBy = true; if (projectedName && this._aliasToGroupByFieldName[projectedName]) { const aliasedFieldName = this._aliasToGroupByFieldName[projectedName]; if (!fieldName || fieldName.toLocaleLowerCase() === (projectedName || "").toLocaleLowerCase()) { fieldName = aliasedFieldName; } } else if (fieldName && Object.keys(this._aliasToGroupByFieldName) .reduce((result, next) => result || next === fieldName, false)) { fieldName = this._aliasToGroupByFieldName[fieldName]; } this._selectTokens.push(GroupByKeyToken_js_1.GroupByKeyToken.create(fieldName, projectedName)); } _groupBySum(fieldName, projectedName = null) { this._assertNoRawQuery(); this._isGroupBy = true; fieldName = this._ensureValidFieldName(fieldName, false); this._selectTokens.push(GroupBySumToken_js_1.GroupBySumToken.create(fieldName, projectedName)); } _groupByCount(projectedName = null) { this._assertNoRawQuery(); this._isGroupBy = true; this._selectTokens.push(GroupByCountToken_js_1.GroupByCountToken.create(projectedName)); } _whereTrue() { const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, null); tokens.push(TrueToken_js_1.TrueToken.INSTANCE); } _moreLikeThis() { this._appendOperatorIfNeeded(this._whereTokens); const token = new MoreLikeThisToken_js_1.MoreLikeThisToken(); this._whereTokens.push(token); this._isInMoreLikeThis = true; return new MoreLikeThisScope_js_1.MoreLikeThisScope(token, v => this._addQueryParameter(v), () => this._isInMoreLikeThis = false); } _include(pathOrIncludes) { if (!pathOrIncludes) { return; } if (TypeUtil_js_1.TypeUtil.isString(pathOrIncludes)) { if (this._theSession) { this._theSession.assertNoIncludesInNonTrackingSession(); } this._documentIncludes.add(pathOrIncludes); return; } const { documentsToInclude } = pathOrIncludes; if (documentsToInclude && documentsToInclude.size > 0) { if (this._theSession) { this._theSession.assertNoIncludesInNonTrackingSession(); } for (const doc of documentsToInclude) { this._documentIncludes.add(doc); } } this._includeCounters(pathOrIncludes.alias, pathOrIncludes.countersToIncludeBySourcePath); if (pathOrIncludes.timeSeriesToIncludeBySourceAlias) { this._includeTimeSeries(pathOrIncludes.alias, pathOrIncludes.timeSeriesToIncludeBySourceAlias); } if (pathOrIncludes.revisionsToIncludeByDateTime) { this._includeRevisionsByDate(pathOrIncludes.revisionsToIncludeByDateTime); } if (pathOrIncludes.revisionsToIncludeByChangeVector) { this._includeRevisionsByChangeVector(pathOrIncludes.revisionsToIncludeByChangeVector); } if (pathOrIncludes.compareExchangeValuesToInclude && pathOrIncludes.compareExchangeValuesToInclude.size > 0) { if (this._theSession) { this._theSession.assertNoIncludesInNonTrackingSession(); } this._compareExchangeValueIncludesTokens = []; for (const compareExchangeValue of pathOrIncludes.compareExchangeValuesToInclude) { this._compareExchangeValueIncludesTokens.push(CompareExchangeValueIncludesToken_js_1.CompareExchangeValueIncludesToken.create(compareExchangeValue)); } } } // TBD: public void Include(Expression<Func<T, object>> path) _take(count) { this._pageSize = count; } _skip(count) { this._start = count; } /** * Filter the results from the index using the specified where clause. */ _whereLucene(fieldName, whereClause, exact) { fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const options = exact ? new WhereToken_js_1.WhereOptions({ exact }) : null; const whereToken = WhereToken_js_1.WhereToken.create("Lucene", fieldName, this._addQueryParameter(whereClause), options); tokens.push(whereToken); } /** * Simplified method for opening a new clause within the query */ _openSubclause() { this._currentClauseDepth++; const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, null); tokens.push(OpenSubclauseToken_js_1.OpenSubclauseToken.create()); } /** * Simplified method for closing a clause within the query */ _closeSubclause() { this._currentClauseDepth--; const tokens = this._getCurrentWhereTokens(); tokens.push(CloseSubclauseToken_js_1.CloseSubclauseToken.create()); } _whereEquals(fieldNameOrWhereParams, value, exact = false) { if (!TypeUtil_js_1.TypeUtil.isObject(fieldNameOrWhereParams)) { const params = new WhereParams_js_1.WhereParams(); params.fieldName = fieldNameOrWhereParams; params.value = value; params.exact = exact; this._whereEquals(params); return; } const whereParams = fieldNameOrWhereParams; if (this._negate) { this._negate = false; this._whereNotEquals(whereParams); return; } whereParams.fieldName = this._ensureValidFieldName(whereParams.fieldName, whereParams.nestedPath); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); if (this._ifValueIsMethod("Equals", whereParams, tokens)) { return; } const transformToEqualValue = this._transformValue(whereParams); const addQueryParameter = this._addQueryParameter(transformToEqualValue); const whereToken = WhereToken_js_1.WhereToken.create("Equals", whereParams.fieldName, addQueryParameter, new WhereToken_js_1.WhereOptions({ exact: whereParams.exact })); tokens.push(whereToken); } _ifValueIsMethod(op, whereParams, tokens) { if (whereParams.value instanceof MethodCall_js_1.MethodCall) { const mc = whereParams.value; const args = mc.args.map(() => null); for (let i = 0; i < mc.args.length; i++) { args[i] = this._addQueryParameter(mc.args[i]); } let token; const type = mc.constructor.name; if (CmpXchg_js_1.CmpXchg.name === type) { token = WhereToken_js_1.WhereToken.create(op, whereParams.fieldName, null, new WhereToken_js_1.WhereOptions({ methodType: "CmpXchg", parameters: args, property: mc.accessPath, exact: whereParams.exact })); } else { (0, index_js_1.throwError)("InvalidArgumentException", `Unknown method ${type}.`); } tokens.push(token); return true; } return false; } _whereNotEquals(fieldNameOrWhereParams, value, exact = false) { let whereParams; if (TypeUtil_js_1.TypeUtil.isString(fieldNameOrWhereParams)) { whereParams = new WhereParams_js_1.WhereParams(); whereParams.fieldName = fieldNameOrWhereParams; whereParams.value = value; whereParams.exact = exact; return this._whereNotEquals(whereParams); } whereParams = fieldNameOrWhereParams; if (this._negate) { this._negate = false; this._whereEquals(whereParams); return; } const transformToEqualValue = this._transformValue(whereParams); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); whereParams.fieldName = this._ensureValidFieldName(whereParams.fieldName, whereParams.nestedPath); if (this._ifValueIsMethod("NotEquals", whereParams, tokens)) { return; } const whereToken = WhereToken_js_1.WhereToken.create("NotEquals", whereParams.fieldName, this._addQueryParameter(transformToEqualValue), new WhereToken_js_1.WhereOptions(whereParams.exact)); tokens.push(whereToken); } _negateNext() { this._negate = !this._negate; } /** * Check that the field has one of the specified value */ _whereIn(fieldName, values, exact = false) { this._assertMethodIsCurrentlySupported("whereIn"); fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const whereToken = WhereToken_js_1.WhereToken.create("In", fieldName, this._addQueryParameter(this._transformCollection(fieldName, AbstractDocumentQuery._unpackCollection(values)))); tokens.push(whereToken); } _whereStartsWith(fieldName, value, exact = false) { this._assertMethodIsCurrentlySupported("whereStartsWith"); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.fieldName = fieldName; whereParams.value = value; whereParams.allowWildcards = true; const transformToEqualValue = this._transformValue(whereParams); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); whereParams.fieldName = this._ensureValidFieldName(whereParams.fieldName, whereParams.nestedPath); this._negateIfNeeded(tokens, whereParams.fieldName); const whereToken = WhereToken_js_1.WhereToken.create("StartsWith", whereParams.fieldName, this._addQueryParameter(transformToEqualValue), new WhereToken_js_1.WhereOptions({ exact })); tokens.push(whereToken); } /** * Matches fields which ends with the specified value. */ _whereEndsWith(fieldName, value, exact = false) { this._assertMethodIsCurrentlySupported("whereEndsWith"); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.fieldName = fieldName; whereParams.value = value; whereParams.allowWildcards = true; const transformToEqualValue = this._transformValue(whereParams); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); whereParams.fieldName = this._ensureValidFieldName(whereParams.fieldName, whereParams.nestedPath); this._negateIfNeeded(tokens, whereParams.fieldName); const whereToken = WhereToken_js_1.WhereToken.create("EndsWith", whereParams.fieldName, this._addQueryParameter(transformToEqualValue), new WhereToken_js_1.WhereOptions({ exact })); tokens.push(whereToken); } /** * Matches fields where the value is between the specified start and end, inclusive */ _whereBetween(fieldName, start, end, exact = false) { this._assertMethodIsCurrentlySupported("whereBetween"); fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const startParams = new WhereParams_js_1.WhereParams(); startParams.value = start; startParams.fieldName = fieldName; const endParams = new WhereParams_js_1.WhereParams(); endParams.value = end; endParams.fieldName = fieldName; const fromParameterName = this._addQueryParameter(!start ? "*" : this._transformValue(startParams, true)); const toParameterName = this._addQueryParameter(!end ? "NULL" : this._transformValue(endParams, true)); const whereToken = WhereToken_js_1.WhereToken.create("Between", fieldName, null, new WhereToken_js_1.WhereOptions({ exact, from: fromParameterName, to: toParameterName })); tokens.push(whereToken); } /** * Matches fields where the value is greater than the specified value */ _whereGreaterThan(fieldName, value, exact = false) { fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.value = value; whereParams.fieldName = fieldName; const parameter = this._addQueryParameter(!value ? "*" : this._transformValue(whereParams, true)); const whereToken = WhereToken_js_1.WhereToken.create("GreaterThan", fieldName, parameter, new WhereToken_js_1.WhereOptions({ exact })); tokens.push(whereToken); } /** * Matches fields where the value is greater than or equal to the specified value */ _whereGreaterThanOrEqual(fieldName, value, exact = false) { fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.value = value; whereParams.fieldName = fieldName; const parameter = this._addQueryParameter(!value ? "*" : this._transformValue(whereParams, true)); const whereToken = WhereToken_js_1.WhereToken.create("GreaterThanOrEqual", fieldName, parameter, new WhereToken_js_1.WhereOptions({ exact })); tokens.push(whereToken); } _whereLessThan(fieldName, value, exact = false) { fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.value = value; whereParams.fieldName = fieldName; const parameter = this._addQueryParameter(!value ? "NULL" : this._transformValue(whereParams, true)); const whereToken = WhereToken_js_1.WhereToken.create("LessThan", fieldName, parameter, new WhereToken_js_1.WhereOptions({ exact })); tokens.push(whereToken); } _whereLessThanOrEqual(fieldName, value, exact = false) { fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.value = value; whereParams.fieldName = fieldName; const parameter = this._addQueryParameter(!value ? "NULL" : this._transformValue(whereParams, true)); const whereToken = WhereToken_js_1.WhereToken.create("LessThanOrEqual", fieldName, parameter, new WhereToken_js_1.WhereOptions({ exact })); tokens.push(whereToken); } /** * Matches fields where Regex.IsMatch(filedName, pattern) */ _whereRegex(fieldName, pattern) { this._assertMethodIsCurrentlySupported("whereRegex"); fieldName = this._ensureValidFieldName(fieldName, false); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); this._negateIfNeeded(tokens, fieldName); const whereParams = new WhereParams_js_1.WhereParams(); whereParams.value = pattern; whereParams.fieldName = fieldName; const parameter = this._addQueryParameter(this._transformValue(whereParams)); const whereToken = WhereToken_js_1.WhereToken.create("Regex", fieldName, parameter); tokens.push(whereToken); } _andAlso(wrapPreviousQueryClauses = false) { const tokens = this._getCurrentWhereTokens(); if (!tokens || !tokens.length) { return; } if (tokens.at(-1) instanceof QueryOperatorToken_js_1.QueryOperatorToken) { (0, index_js_1.throwError)("InvalidOperationException", "Cannot add AND, previous token was already an operator token."); } if (wrapPreviousQueryClauses) { tokens.unshift(OpenSubclauseToken_js_1.OpenSubclauseToken.create()); tokens.push(CloseSubclauseToken_js_1.CloseSubclauseToken.create()); tokens.push(QueryOperatorToken_js_1.QueryOperatorToken.AND); } else { tokens.push(QueryOperatorToken_js_1.QueryOperatorToken.AND); } } /** * Add an OR to the query */ _orElse() { const tokens = this._getCurrentWhereTokens(); if (!tokens && !tokens.length) { return; } if (tokens.at(-1) instanceof QueryOperatorToken_js_1.QueryOperatorToken) { (0, index_js_1.throwError)("InvalidOperationException", "Cannot add OR, previous token was already an operator token."); } tokens.push(QueryOperatorToken_js_1.QueryOperatorToken.OR); } setFilterMode(on) { return new FilterModeScope(this._filterModeStack, on); } /** * Specifies a boost weight to the previous where clause. * The higher the boost factor, the more relevant the term will be. * <p> * boosting factor where 1.0 is default, less than 1.0 is lower weight, greater than 1.0 is higher weight * <p> * http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boosting%20a%20Term */ _boost(boost) { this._assertMethodIsCurrentlySupported("boost"); if (boost === 1.0) { return; } if (boost < 0.0) { (0, index_js_1.throwError)("InvalidArgumentException", "Boost factor must be a non-negative number"); } const tokens = this._getCurrentWhereTokens(); let last = tokens.length ? tokens.at(-1) : null; if (last instanceof WhereToken_js_1.WhereToken) { last.options.boost = boost; } else if (last instanceof CloseSubclauseToken_js_1.CloseSubclauseToken) { const parameter = this._addQueryParameter(boost); const close = last; let openSubclauseToSkip = 0; let index = tokens.indexOf(last); while (last && index > 0) { index--; last = tokens[index]; // find the previous option if (last instanceof CloseSubclauseToken_js_1.CloseSubclauseToken) { // We have to count how many inner subclauses were inside current subclause openSubclauseToSkip++; } else if (last instanceof OpenSubclauseToken_js_1.OpenSubclauseToken && openSubclauseToSkip > 0) { // Inner subclause open - we have to skip it because we want to match only the leftmost opening. openSubclauseToSkip--; } else if (last instanceof OpenSubclauseToken_js_1.OpenSubclauseToken) { last.boostParameterName = parameter; close.boostParameterName = parameter; } } } else { (0, index_js_1.throwError)("InvalidOperationException", "Cannot apply boost"); } } /** * Specifies a fuzziness factor to the single word term in the last where clause * <p> * 0.0 to 1.0 where 1.0 means closer match * <p> * https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Fuzzy%20Searches */ _fuzzy(fuzzy) { this._assertMethodIsCurrentlySupported("fuzzy"); const tokens = this._getCurrentWhereTokens(); if (!tokens && !tokens.length) { (0, index_js_1.throwError)("InvalidOperationException", "Fuzzy can only be used right after where clause."); } const whereToken = tokens.at(-1); if (!(whereToken instanceof WhereToken_js_1.WhereToken)) { (0, index_js_1.throwError)("InvalidOperationException", "Fuzzy can only be used right after where clause."); } if (whereToken.whereOperator !== "Equals") { (0, index_js_1.throwError)("InvalidOperationException", "Fuzzy can only be used right after where clause with equals operator"); } if (fuzzy < 0.0 || fuzzy > 1.0) { (0, index_js_1.throwError)("InvalidArgumentException", "Fuzzy distance must be between 0.0 and 1.0."); } whereToken.options.fuzzy = fuzzy; } /** * Specifies a proximity distance for the phrase in the last search clause * <p> * https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Proximity%20Searches */ _proximity(proximity) { this._assertMethodIsCurrentlySupported("proximity"); const tokens = this._getCurrentWhereTokens(); if (!tokens && !tokens.length) { (0, index_js_1.throwError)("InvalidOperationException", "Proximity can only be used right after search clause."); } const whereToken = tokens.at(-1); if (!(whereToken instanceof WhereToken_js_1.WhereToken)) { (0, index_js_1.throwError)("InvalidOperationException", "Proximity can only be used right after search clause."); } if (whereToken.whereOperator !== "Search") { (0, index_js_1.throwError)("InvalidOperationException", "Proximity can only be used right after search clause"); } if (proximity < 0) { (0, index_js_1.throwError)("InvalidArgumentException", "Proximity distance must be a number greater than or equal to 0"); } whereToken.options.proximity = proximity; } _orderBy(field, orderingOrOptions = "String") { if (TypeUtil_js_1.TypeUtil.isString(orderingOrOptions)) { this._assertNoRawQuery(); const f = this._ensureValidFieldName(field, false); this._orderByTokens.push(OrderByToken_js_1.OrderByToken.createAscending(f, { ordering: orderingOrOptions })); } else { const sorterName = orderingOrOptions.sorterName; if (StringUtil_js_1.StringUtil.isNullOrEmpty(sorterName)) { (0, index_js_1.throwError)("InvalidArgumentException", "SorterName cannot be null or empty"); } this._assertNoRawQuery(); const f = this._ensureValidFieldName(field, false); this._orderByTokens.push(OrderByToken_js_1.OrderByToken.createAscending(f, orderingOrOptions)); } } _orderByDescending(field, orderingOrOptions = "String") { if (TypeUtil_js_1.TypeUtil.isString(orderingOrOptions)) { this._assertNoRawQuery(); const f = this._ensureValidFieldName(field, false); this._orderByTokens.push(OrderByToken_js_1.OrderByToken.createDescending(f, { ordering: orderingOrOptions })); } else { const sorterName = orderingOrOptions.sorterName; if (StringUtil_js_1.StringUtil.isNullOrEmpty(sorterName)) { (0, index_js_1.throwError)("InvalidArgumentException", "SorterName cannot be null or empty"); } this._assertNoRawQuery(); const f = this._ensureValidFieldName(field, false); this._orderByTokens.push(OrderByToken_js_1.OrderByToken.createDescending(f, orderingOrOptions)); } } _orderByScore() { this._assertNoRawQuery(); this._orderByTokens.push(OrderByToken_js_1.OrderByToken.scoreAscending); } _orderByScoreDescending() { this._assertNoRawQuery(); this._orderByTokens.push(OrderByToken_js_1.OrderByToken.scoreDescending); } /** * Provide statistics about the query, such as total count of matching records */ _statistics(statsCallback) { this._queryStats.requestedByUser = true; statsCallback(this._queryStats); } // TBD public void InvokeAfterStreamExecuted(BlittableJsonReaderObject result) /** * Generates the index query. */ _generateIndexQuery(query) { const indexQuery = new IndexQuery_js_1.IndexQuery(); indexQuery.query = query; indexQuery.waitForNonStaleResults = this._theWaitForNonStaleResults; indexQuery.waitForNonStaleResultsTimeout = this._timeout; indexQuery.queryParameters = this._queryParameters; indexQuery.disableCaching = this._disableCaching; indexQuery.projectionBehavior = this.projectionBehavior; indexQuery.skipStatistics = !this._queryStats.requestedByUser; return indexQuery; } /** * Perform a search for documents which fields that match the searchTerms. * If there is more than a single term, each of them will be checked independently. */ _search(fieldName, searchTerms, operator = "OR") { this._assertMethodIsCurrentlySupported("search"); const tokens = this._getCurrentWhereTokens(); this._appendOperatorIfNeeded(tokens); fieldName = this._ensureValidFieldName(fieldName, false); this._negateIfNeeded(tokens, fieldName); const whereToken = WhereToken_js_1.WhereToken.create("Search", fieldName, this._addQueryParameter(searchTerms), new WhereToken_js_1.WhereOptions({ search: operator })); tokens.push(whereToken); } toString(compatibilityMode = false) { if (this._queryRaw) { if (compatibilityMode) { return this._queryRaw; } const rawQueryText = new StringBuilder_js_1.StringBuilder(this._queryRaw); this._buildPagination(rawQueryText); return rawQueryText.toString(); } if (this._currentClauseDepth) { (0, index_js_1.throwError)("InvalidOperationException", "A clause was not closed correctly within this query, current clause depth = " + this._currentClauseDepth); } const queryText = new StringBuilder_js_1.StringBuilder(); this._buildDeclare(queryText); this._buildFrom(queryText); this._buildGroupBy(queryText); this._buildWhere(queryText); this._buildOrderBy(queryText); this._buildLoad(queryText); this._buildFilter(queryText); this._buildSelect(queryText); this._buildInclude(queryText); if (!compatibilityMode) { this._buildPagination(queryText); } return queryText.toString(); } _buildPagination(queryText) { if (this._start > 0 || !TypeUtil_js_1.TypeUtil.isNullOrUndefined(this._pageSize)) { queryText .append(" limit $") .append(this._addQueryParameter(this._start)) .append(", $") .append(this._addQueryParameter(this._pageSize)); } if (this._filterTokens.length > 0 && this._filterLimit > 0) { queryText .append(" filter_limit $") .append(this._addQueryParameter(this._filterLimit)); } } _buildInclude(queryText) { if (!this._documentIncludes.size && !this._highlightingTokens.length && !this._explanationToken && !this._queryTimings && !this._counterIncludesTokens && !this._revisionsIncludesTokens && !this._timeSeriesIncludesTokens && !this._compareExchangeValueIncludesTokens) { return; } queryText.append(" include "); const firstRef = { value: true }; for (const include of this._documentIncludes) { if (!firstRef.value) { queryText.append(","); } firstRef.value = false; let escapedInclude; if (IncludesUtil_js_1.IncludesUtil.requiresQuotes(include, x => escapedInclude = x)) { queryText.append("'"); queryText.append(escapedInclude); queryText.append("'"); } else { queryText.append(include); } } this._writeIncludeTokens(this._counterIncludesTokens, firstRef, queryText); this._writeIn