ravendb
Version:
RavenDB client for Node.js
1,118 lines • 82.3 kB
JavaScript
"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