Skip to content
351 changes: 351 additions & 0 deletions handwritten/firestore/dev/src/pipelines/expression.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add @returns tags and usage examples to expression docs where those are missing

Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ import {
fieldOrExpression,
isFirestoreValue,
isString,
toField,
valueToDefaultExpr,
vectorToExpr,
} from './pipeline-util';
import {HasUserData, Serializer, validateUserInput} from '../serializer';
import {cast} from '../util';
import {GeoPoint} from '../geo-point';
import {OptionsUtil} from './options-util';

/**
* @beta
Expand Down Expand Up @@ -3100,6 +3103,85 @@ export abstract class Expression
]).asBoolean();
}

// /**
// * Evaluates if the result of this `expression` is between
// * the `lowerBound` (inclusive) and `upperBound` (inclusive).
// *
// * @example
// * ```
// * // Evaluate if the 'tireWidth' is between 2.2 and 2.4
// * field('tireWidth').between(constant(2.2), constant(2.4))
// *
// * // This is functionally equivalent to
// * and(field('tireWidth').greaterThanOrEqual(contant(2.2)), field('tireWidth').lessThanOrEqual(constant(2.4)))
// * ```
// *
// * @param lowerBound - Lower bound (inclusive) of the range.
// * @param upperBound - Upper bound (inclusive) of the range.
// */
// between(lowerBound: Expression, upperBound: Expression): BooleanExpression;
//
// /**
// * Evaluates if the result of this `expression` is between
// * the `lowerBound` (inclusive) and `upperBound` (inclusive).
// *
// * @example
// * ```
// * // Evaluate if the 'tireWidth' is between 2.2 and 2.4
// * field('tireWidth').between(2.2, 2.4)
// *
// * // This is functionally equivalent to
// * and(field('tireWidth').greaterThanOrEqual(2.2), field('tireWidth').lessThanOrEqual(2.4))
// * ```
// *
// * @param lowerBound - Lower bound (inclusive) of the range.
// * @param upperBound - Upper bound (inclusive) of the range.
// */
// between(lowerBound: unknown, upperBound: unknown): BooleanExpression;
//
// between(lowerBound: unknown, upperBound: unknown): BooleanExpression {
// return new FunctionExpression('between', [
// this,
// valueToDefaultExpr(lowerBound),
// valueToDefaultExpr(upperBound),
// ]).asBoolean();
// }
//
// /**
// * Evaluates to an HTML-formatted text snippet that renders terms matching
// * the search query in `<b>bold</b>`.
// *
// * @remarks This Expression can only be used within a `Search` stage.
// *
// * @param rquery Define the search query using the search DSL.
// */
// snippet(rquery: string): Expression;
//
// /**
// * Evaluates to an HTML-formatted text snippet that renders terms matching
// * the search query in `<b>bold</b>`.
// *
// * @remarks This Expression can only be used within a `Search` stage.
// *
// * @param options Define how snippeting behaves.
// */
// snippet(options: firestore.Pipelines.SnippetOptions): Expression;
//
// snippet(
// queryOrOptions: string | firestore.Pipelines.SnippetOptions,
// ): Expression {
// const options: firestore.Pipelines.SnippetOptions = isString(queryOrOptions)
// ? {rquery: queryOrOptions}
// : queryOrOptions;
// const rquery = options.rquery;
// const internalOptions = {
// maxSnippetWidth: options.maxSnippetWidth,
// maxSnippets: options.maxSnippets,
// separator: options.separator,
// };
// return new SnippetExpression([this, constant(rquery)], internalOptions);
// }

// TODO(new-expression): Add new expression method definitions above this line

/**
Expand Down Expand Up @@ -3351,6 +3433,35 @@ export class Field
readonly expressionType: firestore.Pipelines.ExpressionType = 'Field';
selectable = true as const;

/**
* Perform a full-text search on this field.
*
* @remarks This Expression can only be used within a `Search` stage.
*
* @param rquery Define the search query using the rquery DTS.
*/
matches(rquery: string | Expression): BooleanExpression {
return new FunctionExpression('matches', [
this,
valueToDefaultExpr(rquery),
]).asBoolean();
}

/**
* Evaluates to the distance in meters between the location specified
* by this field and the query location.
*
* @remarks This Expression can only be used within a `Search` stage.
*
* @param location - Compute distance to this GeoPoint.
*/
geoDistance(location: GeoPoint | Expression): Expression {
return new FunctionExpression('geo_distance', [
this,
valueToDefaultExpr(location),
]).asBoolean();
}

/**
* @beta
* @internal
Expand Down Expand Up @@ -3686,6 +3797,51 @@ export class FunctionExpression extends Expression {
}
}

/**
* SnippetExpression extends from FunctionExpression because it
* supports options and requires the options util.
*/
export class SnippetExpression extends FunctionExpression {
/**
* @private
* @internal
*/
get _optionsUtil(): OptionsUtil {
return new OptionsUtil({
maxSnippetWidth: {
serverName: 'max_snippet_width',
},
maxSnippets: {
serverName: 'max_snippets',
},
separator: {
serverName: 'separator',
},
});
}

/**
* @hideconstructor
*/
constructor(
params: Expression[],
private _options?: {},
) {
super('snippet', params);
}

_toProto(serializer: Serializer): api.IValue {
const proto = super._toProto(serializer);
proto.functionValue!.options = this._optionsUtil.getOptionsProto(
serializer,
this._options ?? {},
{},
);

return proto;
}
}

/**
* @beta
* This class defines the base class for Firestore `Pipeline` functions, which can be evaluated within pipeline
Expand Down Expand Up @@ -10258,6 +10414,201 @@ export function isType(
return fieldOrExpression(fieldNameOrExpression).isType(type);
}

// /**
// * Perform a full-text search on the specified field.
// *
// * @remarks This Expression can only be used within a `Search` stage.
// *
// * @param searchField Search the specified field.
// * @param rquery Define the search query using the search DSL.
// */
// export function matches(
// searchField: string | Field,
// rquery: string | Expression,
// ): BooleanExpression {
// return toField(searchField).matches(rquery);
// }

/**
* Perform a full-text search on the document.
*
* @remarks This Expression can only be used within a `Search` stage.
*
* @param rquery Define the search query using the rquery DTS.
*/
export function documentMatches(
rquery: string | Expression,
): BooleanExpression {
return new FunctionExpression('document_matches', [
valueToDefaultExpr(rquery),
]).asBoolean();
}

/**
* Evaluates to the search score that reflects the topicality of the document
* to all the text predicates (for example: `documentMatches`)
* in the search query. If `SearchOptions.query` is not set or does not contain
* any text predicates, then this topicality score will always be `0`.
*
* @remarks This Expression can only be used within a `Search` stage.
*/
export function score(): Expression {
return new FunctionExpression('score', []).asBoolean();
}

// /**
// * Evaluates to an HTML-formatted text snippet that highlights terms matching
// * the search query in `<b>bold</b>`.
// *
// * @remarks This Expression can only be used within a `Search` stage.
// *
// * @param searchField Search the specified field for matching terms.
// * @param rquery Define the search query using the search DSL.
// */
// export function snippet(
// searchField: string | Field,
// rquery: string,
// ): Expression;
//
// /**
// * Evaluates to an HTML-formatted text snippet that highlights terms matching
// * the search query in `<b>bold</b>`.
// *
// * @remarks This Expression can only be used within a `Search` stage.
// *
// * @param searchField Search the specified field for matching terms.
// * @param options Define the search query using the search DSL.
// */
// export function snippet(
// searchField: string | Field,
// options: firestore.Pipelines.SnippetOptions,
// ): Expression;
// export function snippet(
// field: string | Field,
// queryOrOptions: string | firestore.Pipelines.SnippetOptions,
// ): Expression {
// return toField(field).snippet(
// isString(queryOrOptions) ? {rquery: queryOrOptions} : queryOrOptions,
// );
// }

/**
* Evaluates to the distance in meters between the location in the specified
* field and the query location.
*
* @remarks This Expression can only be used within a `Search` stage.
*
* @param fieldName - Specifies the field in the document which contains
* the first GeoPoint for distance computation.
* @param location - Compute distance to this GeoPoint.
*/
export function geoDistance(
fieldName: string | Field,
location: GeoPoint | Expression,
): Expression {
return toField(fieldName).geoDistance(location);
}
//
// /**
// * Evaluates if the value in the field specified by `fieldName` is between
// * the evaluated values for `lowerBound` (inclusive) and `upperBound` (inclusive).
// *
// * @example
// * ```
// * // Evaluate if the 'tireWidth' is between 2.2 and 2.4
// * between('tireWidth', constant(2.2), constant(2.4))
// *
// * // This is functionally equivalent to
// * and(greaterThanOrEqual('tireWidth', constant(2.2)), lessThanOrEqual('tireWidth', constant(2.4)))
// * ```
// *
// * @param fieldName - Evaluate if the value stored in this field is between the lower and upper bounds.
// * @param lowerBound - Lower bound (inclusive) of the range.
// * @param upperBound - Upper bound (inclusive) of the range.
// */
// export function between(
// fieldName: string,
// lowerBound: Expression,
// upperBound: Expression,
// ): BooleanExpression;
//
// /**
// * Evaluates if the value in the field specified by `fieldName` is between
// * the values for `lowerBound` (inclusive) and `upperBound` (inclusive).
// *
// * @example
// * ```
// * // Evaluate if the 'tireWidth' is between 2.2 and 2.4
// * between('tireWidth', 2.2, 2.4)
// *
// * // This is functionally equivalent to
// * and(greaterThanOrEqual('tireWidth', 2.2), lessThanOrEqual('tireWidth', 2.4))
// * ```
// *
// * @param fieldName - Evaluate if the value stored in this field is between the lower and upper bounds.
// * @param lowerBound - Lower bound (inclusive) of the range.
// * @param upperBound - Upper bound (inclusive) of the range.
// */
// export function between(
// fieldName: string,
// lowerBound: unknown,
// upperBound: unknown,
// ): BooleanExpression;
//
// /**
// * Evaluates if the result of the specified `expression` is between
// * the results of `lowerBound` (inclusive) and `upperBound` (inclusive).
// *
// * @example
// * ```
// * // Evaluate if the 'tireWidth' is between 2.2 and 2.4
// * between(field('tireWidth'), constant(2.2), constant(2.4))
// *
// * // This is functionally equivalent to
// * and(greaterThanOrEqual(field('tireWidth'), constant(2.2)), lessThanOrEqual(field('tireWidth'), constant(2.4)))
// * ```
// *
// * @param expression - Evaluate if the result of this expression is between the lower and upper bounds.
// * @param lowerBound - Lower bound (inclusive) of the range.
// * @param upperBound - Upper bound (inclusive) of the range.
// */
// export function between(
// expression: Expression,
// lowerBound: Expression,
// upperBound: Expression,
// ): BooleanExpression;
//
// /**
// * Evaluates if the result of the specified `expression` is between
// * the `lowerBound` (inclusive) and `upperBound` (inclusive).
// *
// * @example
// * ```
// * // Evaluate if the 'tireWidth' is between 2.2 and 2.4
// * between(field('tireWidth'), 2.2, 2.4)
// *
// * // This is functionally equivalent to
// * and(greaterThanOrEqual(field('tireWidth'), 2.2), lessThanOrEqual(field('tireWidth'), 2.4))
// * ```
// *
// * @param expression - Evaluate if the result of this expression is between the lower and upper bounds.
// * @param lowerBound - Lower bound (inclusive) of the range.
// * @param upperBound - Upper bound (inclusive) of the range.
// */
// export function between(
// expression: Expression,
// lowerBound: unknown,
// upperBound: unknown,
// ): BooleanExpression;
//
// export function between(
// expression: Expression | string,
// lowerBound: unknown,
// upperBound: unknown,
// ): BooleanExpression {
// return fieldOrExpression(expression).between(lowerBound, upperBound);
// }

// TODO(new-expression): Add new top-level expression function definitions above this line

/**
Expand Down
Loading
Loading