mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
feat(firestore): add public preview support for full-text search and geo search (#9734)
--------- Co-authored-by: Daniel La Rocque <[email protected]>
This commit is contained in:
committed by
GitHub
co-authored by
Daniel La Rocque
parent
f16431be0c
commit
3dcdae71e8
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"firebase": minor
|
||||
"@firebase/firestore": minor
|
||||
---
|
||||
|
||||
Added public preview support for full-text and geo search in Pipelines.
|
||||
@@ -399,6 +399,9 @@ export function documentId(documentPath: string | DocumentReference): FunctionEx
|
||||
// @public
|
||||
export function documentId(documentPathExpr: Expression): FunctionExpression;
|
||||
|
||||
// @beta
|
||||
export function documentMatches(rquery: string | Expression): BooleanExpression;
|
||||
|
||||
// @public
|
||||
export type DocumentsStageOptions = StageOptions & {
|
||||
docs: Array<string | DocumentReference>;
|
||||
@@ -834,6 +837,8 @@ export class Field extends Expression implements Selectable {
|
||||
readonly expressionType: ExpressionType;
|
||||
// (undocumented)
|
||||
get fieldName(): string;
|
||||
// @beta
|
||||
geoDistance(location: GeoPoint | Expression): Expression;
|
||||
// (undocumented)
|
||||
selectable: true;
|
||||
}
|
||||
@@ -868,11 +873,13 @@ export function floor(fieldName: string): FunctionExpression;
|
||||
// @public
|
||||
export class FunctionExpression extends Expression {
|
||||
constructor(name: string, params: Expression[]);
|
||||
constructor(name: string, params: Expression[], _methodName: string | undefined);
|
||||
// (undocumented)
|
||||
readonly expressionType: ExpressionType;
|
||||
}
|
||||
|
||||
// @beta
|
||||
export function geoDistance(fieldName: string | Field, location: GeoPoint | Expression): Expression;
|
||||
|
||||
// @public
|
||||
export function greaterThan(left: Expression, right: Expression): BooleanExpression;
|
||||
|
||||
@@ -1212,6 +1219,8 @@ export class Pipeline {
|
||||
replaceWith(options: ReplaceWithStageOptions): Pipeline;
|
||||
sample(documents: number): Pipeline;
|
||||
sample(options: SampleStageOptions): Pipeline;
|
||||
// @beta
|
||||
search(options: SearchStageOptions): Pipeline;
|
||||
select(selection: Selectable | string, ...additionalSelections: Array<Selectable | string>): Pipeline;
|
||||
select(options: SelectStageOptions): Pipeline;
|
||||
sort(ordering: Ordering, ...additionalOrderings: Ordering[]): Pipeline;
|
||||
@@ -1376,6 +1385,16 @@ export type SampleStageOptions = StageOptions & OneOf<{
|
||||
documents: number;
|
||||
}>;
|
||||
|
||||
// @beta
|
||||
export function score(): Expression;
|
||||
|
||||
// @beta
|
||||
export type SearchStageOptions = StageOptions & {
|
||||
query: BooleanExpression | string;
|
||||
sort?: Ordering | Ordering[];
|
||||
addFields?: Selectable[];
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface Selectable {
|
||||
// (undocumented)
|
||||
@@ -1411,11 +1430,11 @@ export function sqrt(expression: Expression): FunctionExpression;
|
||||
export function sqrt(fieldName: string): FunctionExpression;
|
||||
|
||||
// @public
|
||||
export interface StageOptions {
|
||||
export type StageOptions = {
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// @public
|
||||
export function startsWith(fieldName: string, prefix: string): BooleanExpression;
|
||||
|
||||
@@ -399,6 +399,9 @@ export function documentId(documentPath: string | DocumentReference): FunctionEx
|
||||
// @public
|
||||
export function documentId(documentPathExpr: Expression): FunctionExpression;
|
||||
|
||||
// @beta
|
||||
export function documentMatches(rquery: string | Expression): BooleanExpression;
|
||||
|
||||
// @public
|
||||
export type DocumentsStageOptions = StageOptions & {
|
||||
docs: Array<string | DocumentReference>;
|
||||
@@ -837,6 +840,8 @@ export class Field extends Expression implements Selectable {
|
||||
readonly expressionType: ExpressionType;
|
||||
// (undocumented)
|
||||
get fieldName(): string;
|
||||
// @beta
|
||||
geoDistance(location: GeoPoint | Expression): Expression;
|
||||
// (undocumented)
|
||||
selectable: true;
|
||||
}
|
||||
@@ -871,11 +876,13 @@ export function floor(fieldName: string): FunctionExpression;
|
||||
// @public
|
||||
export class FunctionExpression extends Expression {
|
||||
constructor(name: string, params: Expression[]);
|
||||
constructor(name: string, params: Expression[], _methodName: string | undefined);
|
||||
// (undocumented)
|
||||
readonly expressionType: ExpressionType;
|
||||
}
|
||||
|
||||
// @beta
|
||||
export function geoDistance(fieldName: string | Field, location: GeoPoint | Expression): Expression;
|
||||
|
||||
// @public
|
||||
export function greaterThan(left: Expression, right: Expression): BooleanExpression;
|
||||
|
||||
@@ -1219,6 +1226,10 @@ export class Pipeline {
|
||||
replaceWith(options: ReplaceWithStageOptions): Pipeline;
|
||||
sample(documents: number): Pipeline;
|
||||
sample(options: SampleStageOptions): Pipeline;
|
||||
// Warning: (ae-incompatible-release-tags) The symbol "search" is marked as @public, but its signature references "SearchStageOptions" which is marked as @beta
|
||||
//
|
||||
// (undocumented)
|
||||
search(options: SearchStageOptions): Pipeline;
|
||||
select(selection: Selectable | string, ...additionalSelections: Array<Selectable | string>): Pipeline;
|
||||
select(options: SelectStageOptions): Pipeline;
|
||||
sort(ordering: Ordering, ...additionalOrderings: Ordering[]): Pipeline;
|
||||
@@ -1398,6 +1409,16 @@ export type SampleStageOptions = StageOptions & OneOf<{
|
||||
documents: number;
|
||||
}>;
|
||||
|
||||
// @beta
|
||||
export function score(): Expression;
|
||||
|
||||
// @beta
|
||||
export type SearchStageOptions = StageOptions & {
|
||||
query: BooleanExpression | string;
|
||||
sort?: Ordering | Ordering[];
|
||||
addFields?: Selectable[];
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface Selectable {
|
||||
// (undocumented)
|
||||
@@ -1433,11 +1454,11 @@ export function sqrt(expression: Expression): FunctionExpression;
|
||||
export function sqrt(fieldName: string): FunctionExpression;
|
||||
|
||||
// @public
|
||||
export interface StageOptions {
|
||||
export type StageOptions = {
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// @public
|
||||
export function startsWith(fieldName: string, prefix: string): BooleanExpression;
|
||||
|
||||
@@ -654,8 +654,6 @@ toc:
|
||||
path: /docs/reference/js/firestore_lite_pipelines.querydocumentsnapshot.md
|
||||
- title: Selectable
|
||||
path: /docs/reference/js/firestore_lite_pipelines.selectable.md
|
||||
- title: StageOptions
|
||||
path: /docs/reference/js/firestore_lite_pipelines.stageoptions.md
|
||||
- title: Timestamp
|
||||
path: /docs/reference/js/firestore_lite_pipelines.timestamp.md
|
||||
- title: VectorValue
|
||||
@@ -719,8 +717,6 @@ toc:
|
||||
path: /docs/reference/js/firestore_pipelines.snapshotmetadata.md
|
||||
- title: SnapshotOptions
|
||||
path: /docs/reference/js/firestore_pipelines.snapshotoptions.md
|
||||
- title: StageOptions
|
||||
path: /docs/reference/js/firestore_pipelines.stageoptions.md
|
||||
- title: Timestamp
|
||||
path: /docs/reference/js/firestore_pipelines.timestamp.md
|
||||
- title: VectorValue
|
||||
|
||||
@@ -35,6 +35,12 @@ export declare class Field extends Expression implements Selectable
|
||||
| [fieldName](./firestore_lite_pipelines.field.md#fieldfieldname) | | string | |
|
||||
| [selectable](./firestore_lite_pipelines.field.md#fieldselectable) | | true | |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [geoDistance(location)](./firestore_lite_pipelines.field.md#fieldgeodistance) | | <b><i>(Public Preview)</i></b> Evaluates to the distance in meters between the location specified by this field and the query location. |
|
||||
|
||||
## Field.alias
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -75,6 +81,31 @@ get fieldName(): string;
|
||||
selectable: true;
|
||||
```
|
||||
|
||||
## Field.geoDistance()
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Evaluates to the distance in meters between the location specified by this field and the query location.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
geoDistance(location: GeoPoint | Expression): Expression;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| location | [GeoPoint](./firestore_lite.geopoint.md#geopoint_class) \| [Expression](./firestore_lite_pipelines.expression.md#expression_class) | Compute distance to this GeoPoint. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Expression](./firestore_lite_pipelines.expression.md#expression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ export declare class FunctionExpression extends Expression
|
||||
| Constructor | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [(constructor)(name, params)](./firestore_lite_pipelines.functionexpression.md#functionexpressionconstructor) | | Constructs a new instance of the <code>FunctionExpression</code> class |
|
||||
| [(constructor)(name, params, \_methodName)](./firestore_lite_pipelines.functionexpression.md#functionexpressionconstructor) | | Constructs a new instance of the <code>FunctionExpression</code> class |
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -51,24 +50,6 @@ constructor(name: string, params: Expression[]);
|
||||
| name | string | |
|
||||
| params | [Expression](./firestore_lite_pipelines.expression.md#expression_class)<!-- -->\[\] | |
|
||||
|
||||
## FunctionExpression.(constructor)
|
||||
|
||||
Constructs a new instance of the `FunctionExpression` class
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
constructor(name: string, params: Expression[], _methodName: string | undefined);
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| name | string | |
|
||||
| params | [Expression](./firestore_lite_pipelines.expression.md#expression_class)<!-- -->\[\] | |
|
||||
| \_methodName | string \| undefined | |
|
||||
|
||||
## FunctionExpression.expressionType
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [countAll()](./firestore_lite_pipelines.md#countall) | Creates an aggregation that counts the total number of stage inputs. |
|
||||
| [currentTimestamp()](./firestore_lite_pipelines.md#currenttimestamp) | Creates an expression that evaluates to the current server timestamp. |
|
||||
| [rand()](./firestore_lite_pipelines.md#rand) | Creates an expression that generates a random number between 0.0 and 1.0 but not including 1.0. |
|
||||
| [score()](./firestore_lite_pipelines.md#score) | <b><i>(Public Preview)</i></b> Evaluates to the search score that reflects the topicality of the document to all of the text predicates (for example: <code>documentMatches</code>) in the search query. If <code>SearchOptions.query</code> is not set or does not contain any text predicates, then this topicality score will always be <code>0</code>. |
|
||||
| <b>function(array, ...)</b> |
|
||||
| [arrayContains(array, element)](./firestore_lite_pipelines.md#arraycontains_a00ea48) | Creates an expression that checks if an array expression contains a specific element. |
|
||||
| [arrayContains(array, element)](./firestore_lite_pipelines.md#arraycontains_7328608) | Creates an expression that checks if an array expression contains a specific element. |
|
||||
@@ -201,6 +202,7 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [exp(fieldName)](./firestore_lite_pipelines.md#exp_e5b0480) | Creates an expression that computes e to the power of the expression's result. |
|
||||
| [first(fieldName)](./firestore_lite_pipelines.md#first_e5b0480) | Creates an aggregation that finds the first value of a field across multiple stage inputs. |
|
||||
| [floor(fieldName)](./firestore_lite_pipelines.md#floor_e5b0480) | Creates an expression that computes the floor of a numeric value. |
|
||||
| [geoDistance(fieldName, location)](./firestore_lite_pipelines.md#geodistance_ea237a8) | <b><i>(Public Preview)</i></b> Evaluates to the distance in meters between the location in the specified field and the query location. |
|
||||
| [greaterThan(fieldName, expression)](./firestore_lite_pipelines.md#greaterthan_1e91657) | Creates an expression that checks if a field's value is greater than an expression. |
|
||||
| [greaterThan(fieldName, value)](./firestore_lite_pipelines.md#greaterthan_65e2f32) | Creates an expression that checks if a field's value is greater than a constant value. |
|
||||
| [greaterThanOrEqual(fieldName, value)](./firestore_lite_pipelines.md#greaterthanorequal_2e16acb) | Creates an expression that checks if a field's value is greater than or equal to an expression. |
|
||||
@@ -340,6 +342,8 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [field(path)](./firestore_lite_pipelines.md#field_34ee07d) | Creates a [Field](./firestore_pipelines.field.md#field_class) instance representing the field at the given path. |
|
||||
| <b>function(pipeline, ...)</b> |
|
||||
| [execute(pipeline)](./firestore_lite_pipelines.md#execute_01df620) | Executes this pipeline and returns a Promise to represent the asynchronous operation.<!-- -->The returned Promise can be used to track the progress of the pipeline execution and retrieve the results (or handle any errors) asynchronously.<!-- -->The pipeline results are returned as a [PipelineSnapshot](./firestore_pipelines.pipelinesnapshot.md#pipelinesnapshot_class) that contains a list of [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) objects. Each [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) typically represents a single key/value map that has passed through all the stages of the pipeline, however this might differ depending on the stages involved in the pipeline. For example:<ul> <li>If there are no stages or only transformation stages, each [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) represents a single document.</li> <li>If there is an aggregation, only a single [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) is returned, representing the aggregated results over the entire dataset .</li> <li>If there is an aggregation stage with grouping, each [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) represents a distinct group and its associated aggregated values.</li> </ul> |
|
||||
| <b>function(rquery, ...)</b> |
|
||||
| [documentMatches(rquery)](./firestore_lite_pipelines.md#documentmatches_d7a12c2) | <b><i>(Public Preview)</i></b> Perform a full-text search on all indexed search fields in the document. |
|
||||
| <b>function(stringExpression, ...)</b> |
|
||||
| [charLength(stringExpression)](./firestore_lite_pipelines.md#charlength_c25a54a) | Creates an expression that calculates the character length of a string expression in UTF-8. |
|
||||
| [endsWith(stringExpression, suffix)](./firestore_lite_pipelines.md#endswith_0a0b889) | Creates an expression that checks if a string expression ends with a given postfix. |
|
||||
@@ -436,7 +440,6 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [DocumentData](./firestore_lite_pipelines.documentdata.md#documentdata_interface) | Document data (for use with [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->) consists of fields mapped to values. |
|
||||
| [FirestoreDataConverter](./firestore_lite_pipelines.firestoredataconverter.md#firestoredataconverter_interface) | Converter used by <code>withConverter()</code> to transform user objects of type <code>AppModelType</code> into Firestore data of type <code>DbModelType</code>.<!-- -->Using the converter allows you to specify generic type arguments when storing and retrieving objects from Firestore.<!-- -->In this context, an "AppModel" is a class that is used in an application to package together related information and functionality. Such a class could, for example, have properties with complex, nested data types, properties used for memoization, properties of types not supported by Firestore (such as <code>symbol</code> and <code>bigint</code>), and helper functions that perform compound operations. Such classes are not suitable and/or possible to store into a Firestore database. Instead, instances of such classes need to be converted to "plain old JavaScript objects" (POJOs) with exclusively primitive properties, potentially nested inside other POJOs or arrays of POJOs. In this context, this type is referred to as the "DbModel" and would be an object suitable for persisting into Firestore. For convenience, applications can implement <code>FirestoreDataConverter</code> and register the converter with Firestore objects, such as <code>DocumentReference</code> or <code>Query</code>, to automatically convert <code>AppModel</code> to <code>DbModel</code> when storing into Firestore, and convert <code>DbModel</code> to <code>AppModel</code> when retrieving from Firestore. |
|
||||
| [Selectable](./firestore_lite_pipelines.selectable.md#selectable_interface) | An interface that represents a selectable expression. |
|
||||
| [StageOptions](./firestore_lite_pipelines.stageoptions.md#stageoptions_interface) | Options defining how a Stage is evaluated. |
|
||||
|
||||
## Type Aliases
|
||||
|
||||
@@ -444,7 +447,7 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| --- | --- |
|
||||
| [AddFieldsStageOptions](./firestore_lite_pipelines.md#addfieldsstageoptions) | Options defining how an AddFieldsStage is evaluated. See [Pipeline.addFields()](./firestore_pipelines.pipeline.md#pipelineaddfields)<!-- -->. |
|
||||
| [AggregateStageOptions](./firestore_lite_pipelines.md#aggregatestageoptions) | Options defining how an AggregateStage is evaluated. See [Pipeline.aggregate()](./firestore_pipelines.pipeline.md#pipelineaggregate)<!-- -->. |
|
||||
| [CollectionGroupStageOptions](./firestore_lite_pipelines.md#collectiongroupstageoptions) | Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) and provides specific settings for how a collection group is identified and processed during pipeline execution.<!-- -->See [PipelineSource.collectionGroup()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollectiongroup) to create a collection group stage. |
|
||||
| [CollectionGroupStageOptions](./firestore_lite_pipelines.md#collectiongroupstageoptions) | Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.md#stageoptions) and provides specific settings for how a collection group is identified and processed during pipeline execution.<!-- -->See [PipelineSource.collectionGroup()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollectiongroup) to create a collection group stage. |
|
||||
| [CollectionStageOptions](./firestore_lite_pipelines.md#collectionstageoptions) | Options defining how a CollectionStage is evaluated. See [PipelineSource.collection()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollection)<!-- -->. |
|
||||
| [DatabaseStageOptions](./firestore_lite_pipelines.md#databasestageoptions) | Options defining how a DatabaseStage is evaluated. See [PipelineSource.database()](./firestore_pipelines.pipelinesource.md#pipelinesourcedatabase)<!-- -->. |
|
||||
| [DistinctStageOptions](./firestore_lite_pipelines.md#distinctstageoptions) | Options defining how a DistinctStage is evaluated. See [Pipeline.distinct()](./firestore_pipelines.pipeline.md#pipelinedistinct)<!-- -->. |
|
||||
@@ -458,10 +461,12 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [Primitive](./firestore_lite_pipelines.md#primitive) | Primitive types. |
|
||||
| [RemoveFieldsStageOptions](./firestore_lite_pipelines.md#removefieldsstageoptions) | Options defining how a RemoveFieldsStage is evaluated. See [Pipeline.removeFields()](./firestore_pipelines.pipeline.md#pipelineremovefields)<!-- -->. |
|
||||
| [ReplaceWithStageOptions](./firestore_lite_pipelines.md#replacewithstageoptions) | Options defining how a ReplaceWithStage is evaluated. See [Pipeline.replaceWith()](./firestore_pipelines.pipeline.md#pipelinereplacewith)<!-- -->. |
|
||||
| [SampleStageOptions](./firestore_lite_pipelines.md#samplestageoptions) | Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) with a specific configuration where only one of the defined sampling methods can be applied.<!-- -->See [Pipeline.sample()](./firestore_pipelines.pipeline.md#pipelinesample) to create a sample stage.. |
|
||||
| [SampleStageOptions](./firestore_lite_pipelines.md#samplestageoptions) | Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.md#stageoptions) with a specific configuration where only one of the defined sampling methods can be applied.<!-- -->See [Pipeline.sample()](./firestore_pipelines.pipeline.md#pipelinesample) to create a sample stage.. |
|
||||
| [SearchStageOptions](./firestore_lite_pipelines.md#searchstageoptions) | <b><i>(Public Preview)</i></b> Options defining how a SearchStage is evaluated. See . |
|
||||
| [SelectStageOptions](./firestore_lite_pipelines.md#selectstageoptions) | Options defining how a SelectStage is evaluated. See [Pipeline.select()](./firestore_pipelines.pipeline.md#pipelineselect)<!-- -->. |
|
||||
| [SetOptions](./firestore_lite_pipelines.md#setoptions) | An options object that configures the behavior of [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->, and calls. These calls can be configured to perform granular merges instead of overwriting the target documents in their entirety by providing a <code>SetOptions</code> with <code>merge: true</code>. |
|
||||
| [SortStageOptions](./firestore_lite_pipelines.md#sortstageoptions) | Options defining how a SortStage is evaluated. See [Pipeline.sort()](./firestore_pipelines.pipeline.md#pipelinesort)<!-- -->. |
|
||||
| [StageOptions](./firestore_lite_pipelines.md#stageoptions) | Options defining how a Stage is evaluated. |
|
||||
| [TimeGranularity](./firestore_lite_pipelines.md#timegranularity) | Specify time granularity for expressions. |
|
||||
| [TimePart](./firestore_lite_pipelines.md#timepart) | Specify time parts for <code>timestampExtract</code> expressions. |
|
||||
| [TimeUnit](./firestore_lite_pipelines.md#timeunit) | Specify time units for expressions. |
|
||||
@@ -545,6 +550,35 @@ rand();
|
||||
|
||||
```
|
||||
|
||||
### score() {:#score}
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Evaluates to the search score that reflects the topicality of the document to all of 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`<!-- -->.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function score(): Expression;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
[Expression](./firestore_lite_pipelines.expression.md#expression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```typescript
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: 'waffles',
|
||||
sort: score().descending()
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## function(array, ...)
|
||||
|
||||
### arrayContains(array, element) {:#arraycontains_a00ea48}
|
||||
@@ -5791,6 +5825,43 @@ export declare function floor(fieldName: string): FunctionExpression;
|
||||
|
||||
A new [Expression](./firestore_pipelines.expression.md#expression_class) representing the floor of the numeric value.
|
||||
|
||||
### geoDistance(fieldName, location) {:#geodistance_ea237a8}
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Evaluates to the distance in meters between the location in the specified field and the query location.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function geoDistance(fieldName: string | Field, location: GeoPoint | Expression): Expression;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| fieldName | string \| [Field](./firestore_lite_pipelines.field.md#field_class) | Specifies the field in the document which contains the first GeoPoint for distance computation. |
|
||||
| location | [GeoPoint](./firestore_lite.geopoint.md#geopoint_class) \| [Expression](./firestore_lite_pipelines.expression.md#expression_class) | Compute distance to this GeoPoint. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Expression](./firestore_lite_pipelines.expression.md#expression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```typescript
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: 'waffles',
|
||||
sort: geoDistance('location', new GeoPoint(37.0, -122.0)).ascending()
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### greaterThan(fieldName, expression) {:#greaterthan_1e91657}
|
||||
|
||||
Creates an expression that checks if a field's value is greater than an expression.
|
||||
@@ -9829,6 +9900,43 @@ const results: PipelineResults = snapshot.results;
|
||||
|
||||
```
|
||||
|
||||
## function(rquery, ...)
|
||||
|
||||
### documentMatches(rquery) {:#documentmatches_d7a12c2}
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Perform a full-text search on all indexed search fields in the document.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function documentMatches(rquery: string | Expression): BooleanExpression;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| rquery | string \| [Expression](./firestore_lite_pipelines.expression.md#expression_class) | Define the search query using the search domain-specific language (DSL). |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[BooleanExpression](./firestore_lite_pipelines.booleanexpression.md#booleanexpression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```typescript
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: documentMatches('waffles OR pancakes')
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## function(stringExpression, ...)
|
||||
|
||||
### charLength(stringExpression) {:#charlength_c25a54a}
|
||||
@@ -11480,7 +11588,7 @@ export declare type AggregateStageOptions = StageOptions & {
|
||||
|
||||
## CollectionGroupStageOptions
|
||||
|
||||
Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) and provides specific settings for how a collection group is identified and processed during pipeline execution.
|
||||
Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.md#stageoptions) and provides specific settings for how a collection group is identified and processed during pipeline execution.
|
||||
|
||||
See [PipelineSource.collectionGroup()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollectiongroup) to create a collection group stage.
|
||||
|
||||
@@ -11663,7 +11771,7 @@ export declare type ReplaceWithStageOptions = StageOptions & {
|
||||
|
||||
## SampleStageOptions
|
||||
|
||||
Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) with a specific configuration where only one of the defined sampling methods can be applied.
|
||||
Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.md#stageoptions) with a specific configuration where only one of the defined sampling methods can be applied.
|
||||
|
||||
See [Pipeline.sample()](./firestore_pipelines.pipeline.md#pipelinesample) to create a sample stage..
|
||||
|
||||
@@ -11676,6 +11784,23 @@ export declare type SampleStageOptions = StageOptions & OneOf<{
|
||||
}>;
|
||||
```
|
||||
|
||||
## SearchStageOptions
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Options defining how a SearchStage is evaluated. See .
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type SearchStageOptions = StageOptions & {
|
||||
query: BooleanExpression | string;
|
||||
sort?: Ordering | Ordering[];
|
||||
addFields?: Selectable[];
|
||||
};
|
||||
```
|
||||
|
||||
## SelectStageOptions
|
||||
|
||||
Options defining how a SelectStage is evaluated. See [Pipeline.select()](./firestore_pipelines.pipeline.md#pipelineselect)<!-- -->.
|
||||
@@ -11714,6 +11839,20 @@ export declare type SortStageOptions = StageOptions & {
|
||||
};
|
||||
```
|
||||
|
||||
## StageOptions
|
||||
|
||||
Options defining how a Stage is evaluated.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type StageOptions = {
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## TimeGranularity
|
||||
|
||||
Specify time granularity for expressions.
|
||||
|
||||
@@ -65,6 +65,7 @@ firestore.pipeline().collection("books")
|
||||
| [replaceWith(options)](./firestore_lite_pipelines.pipeline.md#pipelinereplacewith) | | Fully overwrites all fields in a document with those coming from a map.<p>This stage allows you to emit a map value as a document. Each key of the map becomes a field on the document that contains the corresponding value.<p>Example: |
|
||||
| [sample(documents)](./firestore_lite_pipelines.pipeline.md#pipelinesample) | | Performs a pseudo-random sampling of the documents from the previous stage.<p>This stage will filter documents pseudo-randomly. The parameter specifies how number of documents to be returned.<p>Examples: |
|
||||
| [sample(options)](./firestore_lite_pipelines.pipeline.md#pipelinesample) | | Performs a pseudo-random sampling of the documents from the previous stage.<p>This stage will filter documents pseudo-randomly. The 'options' parameter specifies how sampling will be performed. See [SampleStageOptions](./firestore_pipelines.md#samplestageoptions) for more information. |
|
||||
| [search(options)](./firestore_lite_pipelines.pipeline.md#pipelinesearch) | | <b><i>(Public Preview)</i></b> Add a search stage to the Pipeline. The search stage supports full-text search and geo search expressions. |
|
||||
| [select(selection, additionalSelections)](./firestore_lite_pipelines.pipeline.md#pipelineselect) | | Selects or creates a set of fields from the outputs of previous stages.<p>The selected fields are defined using [Selectable](./firestore_pipelines.selectable.md#selectable_interface) expressions, which can be:<ul> <li><code>string</code> : Name of an existing field</li> <li>[Field](./firestore_pipelines.field.md#field_class)<!-- -->: References an existing field.</li> <li>[AliasedExpression](./firestore_pipelines.aliasedexpression.md#aliasedexpression_class)<!-- -->: Represents the result of a function with an assigned alias name using [Expression.as()](./firestore_pipelines.expression.md#expressionas)</li> </ul><p>If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields()](./firestore_pipelines.pipeline.md#pipelineaddfields) instead if only additions are desired.<p>Example: |
|
||||
| [select(options)](./firestore_lite_pipelines.pipeline.md#pipelineselect) | | Selects or creates a set of fields from the outputs of previous stages.<p>The selected fields are defined using [Selectable](./firestore_pipelines.selectable.md#selectable_interface) expressions, which can be:<ul> <li><code>string</code>: Name of an existing field</li> <li>[Field](./firestore_pipelines.field.md#field_class)<!-- -->: References an existing field.</li> <li>[AliasedExpression](./firestore_pipelines.aliasedexpression.md#aliasedexpression_class)<!-- -->: Represents the result of a function with an assigned alias name using [Expression.as()](./firestore_pipelines.expression.md#expressionas)</li> </ul><p>If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields()](./firestore_pipelines.pipeline.md#pipelineaddfields) instead if only additions are desired.<p>Example: |
|
||||
| [sort(ordering, additionalOrderings)](./firestore_lite_pipelines.pipeline.md#pipelinesort) | | Sorts the documents from previous stages based on one or more [Ordering](./firestore_pipelines.ordering.md#ordering_class) criteria.<p>This stage allows you to order the results of your pipeline. You can specify multiple [Ordering](./firestore_pipelines.ordering.md#ordering_class) instances to sort by multiple fields in ascending or descending order. If documents have the same value for a field used for sorting, the next specified ordering will be used. If all orderings result in equal comparison, the documents are considered equal and the order is unspecified.<p>Example: |
|
||||
@@ -869,6 +870,64 @@ firestore.pipeline().collection("books")
|
||||
|
||||
```
|
||||
|
||||
## Pipeline.search()
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Add a search stage to the Pipeline. The search stage supports full-text search and geo search expressions.
|
||||
|
||||
A limited set of expressions are supported in the search stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
search(options: SearchStageOptions): Pipeline;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| options | [SearchStageOptions](./firestore_lite_pipelines.md#searchstageoptions) | An object that specifies parameters for the stage. A new <code>Pipeline</code> object with this stage appended to the stage list. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Pipeline](./firestore_lite_pipelines.pipeline.md#pipeline_class)
|
||||
|
||||
### Example 1
|
||||
|
||||
|
||||
```typescript
|
||||
// Full-text search example
|
||||
firestore.pipeline().collection("restaurants")
|
||||
.search({
|
||||
query: documentMatches("waffles OR pancakes"),
|
||||
sort: [
|
||||
score().descending(),
|
||||
],
|
||||
addFields: [
|
||||
score().as("searchScore"),
|
||||
]
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Example 2
|
||||
|
||||
|
||||
```typescript
|
||||
// Geo distance search example
|
||||
const queryLocation = new GeoPoint(0, 0);
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: field('location').geoDistance(queryLocation).lessThanOrEqual(1000),
|
||||
sort: [
|
||||
score().descending(),
|
||||
],
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## Pipeline.select()
|
||||
|
||||
Selects or creates a set of fields from the outputs of previous stages.
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
Project: /docs/reference/js/_project.yaml
|
||||
Book: /docs/reference/_book.yaml
|
||||
page_type: reference
|
||||
|
||||
{% comment %}
|
||||
DO NOT EDIT THIS FILE!
|
||||
This is generated by the JS SDK team, and any local changes will be
|
||||
overwritten. Changes should be made in the source code at
|
||||
https://github.com/firebase/firebase-js-sdk
|
||||
{% endcomment %}
|
||||
|
||||
# StageOptions interface
|
||||
Options defining how a Stage is evaluated.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare interface StageOptions
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [rawOptions](./firestore_lite_pipelines.stageoptions.md#stageoptionsrawoptions) | { \[name: string\]: unknown; } | An escape hatch to set options not known at SDK build time. These values will be passed directly to the Firestore backend and not used by the SDK.<!-- -->The option name will be used as provided. And must match the name format used by the backend (hint: use a snake\_case\_name).<!-- -->Raw option values can be any type supported by Firestore (for example: string, boolean, number, map, …). Value types not known to the SDK will be rejected.<!-- -->Values specified in rawOptions will take precedence over any options with the same name set by the SDK.<code>rawOptions</code> supports dot notation, if you want to override a nested option. |
|
||||
|
||||
## StageOptions.rawOptions
|
||||
|
||||
An escape hatch to set options not known at SDK build time. These values will be passed directly to the Firestore backend and not used by the SDK.
|
||||
|
||||
The option name will be used as provided. And must match the name format used by the backend (hint: use a snake\_case\_name).
|
||||
|
||||
Raw option values can be any type supported by Firestore (for example: string, boolean, number, map, …). Value types not known to the SDK will be rejected.
|
||||
|
||||
Values specified in rawOptions will take precedence over any options with the same name set by the SDK.
|
||||
|
||||
`rawOptions` supports dot notation, if you want to override a nested option.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
```
|
||||
@@ -35,6 +35,12 @@ export declare class Field extends Expression implements Selectable
|
||||
| [fieldName](./firestore_pipelines.field.md#fieldfieldname) | | string | |
|
||||
| [selectable](./firestore_pipelines.field.md#fieldselectable) | | true | |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [geoDistance(location)](./firestore_pipelines.field.md#fieldgeodistance) | | <b><i>(Public Preview)</i></b> Evaluates to the distance in meters between the location specified by this field and the query location. |
|
||||
|
||||
## Field.alias
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -75,6 +81,31 @@ get fieldName(): string;
|
||||
selectable: true;
|
||||
```
|
||||
|
||||
## Field.geoDistance()
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Evaluates to the distance in meters between the location specified by this field and the query location.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
geoDistance(location: GeoPoint | Expression): Expression;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| location | [GeoPoint](./firestore_.geopoint.md#geopoint_class) \| [Expression](./firestore_pipelines.expression.md#expression_class) | Compute distance to this GeoPoint. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Expression](./firestore_pipelines.expression.md#expression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ export declare class FunctionExpression extends Expression
|
||||
| Constructor | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [(constructor)(name, params)](./firestore_pipelines.functionexpression.md#functionexpressionconstructor) | | Constructs a new instance of the <code>FunctionExpression</code> class |
|
||||
| [(constructor)(name, params, \_methodName)](./firestore_pipelines.functionexpression.md#functionexpressionconstructor) | | Constructs a new instance of the <code>FunctionExpression</code> class |
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -51,24 +50,6 @@ constructor(name: string, params: Expression[]);
|
||||
| name | string | |
|
||||
| params | [Expression](./firestore_pipelines.expression.md#expression_class)<!-- -->\[\] | |
|
||||
|
||||
## FunctionExpression.(constructor)
|
||||
|
||||
Constructs a new instance of the `FunctionExpression` class
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
constructor(name: string, params: Expression[], _methodName: string | undefined);
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| name | string | |
|
||||
| params | [Expression](./firestore_pipelines.expression.md#expression_class)<!-- -->\[\] | |
|
||||
| \_methodName | string \| undefined | |
|
||||
|
||||
## FunctionExpression.expressionType
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [countAll()](./firestore_pipelines.md#countall) | Creates an aggregation that counts the total number of stage inputs. |
|
||||
| [currentTimestamp()](./firestore_pipelines.md#currenttimestamp) | Creates an expression that evaluates to the current server timestamp. |
|
||||
| [rand()](./firestore_pipelines.md#rand) | Creates an expression that generates a random number between 0.0 and 1.0 but not including 1.0. |
|
||||
| [score()](./firestore_pipelines.md#score) | <b><i>(Public Preview)</i></b> Evaluates to the search score that reflects the topicality of the document to all of the text predicates (for example: <code>documentMatches</code>) in the search query. If <code>SearchOptions.query</code> is not set or does not contain any text predicates, then this topicality score will always be <code>0</code>. |
|
||||
| <b>function(array, ...)</b> |
|
||||
| [arrayContains(array, element)](./firestore_pipelines.md#arraycontains_a00ea48) | Creates an expression that checks if an array expression contains a specific element. |
|
||||
| [arrayContains(array, element)](./firestore_pipelines.md#arraycontains_7328608) | Creates an expression that checks if an array expression contains a specific element. |
|
||||
@@ -201,6 +202,7 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [exp(fieldName)](./firestore_pipelines.md#exp_e5b0480) | Creates an expression that computes e to the power of the expression's result. |
|
||||
| [first(fieldName)](./firestore_pipelines.md#first_e5b0480) | Creates an aggregation that finds the first value of a field across multiple stage inputs. |
|
||||
| [floor(fieldName)](./firestore_pipelines.md#floor_e5b0480) | Creates an expression that computes the floor of a numeric value. |
|
||||
| [geoDistance(fieldName, location)](./firestore_pipelines.md#geodistance_ea237a8) | <b><i>(Public Preview)</i></b> Evaluates to the distance in meters between the location in the specified field and the query location. |
|
||||
| [greaterThan(fieldName, expression)](./firestore_pipelines.md#greaterthan_1e91657) | Creates an expression that checks if a field's value is greater than an expression. |
|
||||
| [greaterThan(fieldName, value)](./firestore_pipelines.md#greaterthan_65e2f32) | Creates an expression that checks if a field's value is greater than a constant value. |
|
||||
| [greaterThanOrEqual(fieldName, value)](./firestore_pipelines.md#greaterthanorequal_2e16acb) | Creates an expression that checks if a field's value is greater than or equal to an expression. |
|
||||
@@ -343,6 +345,8 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [field(path)](./firestore_pipelines.md#field_34ee07d) | Creates a [Field](./firestore_pipelines.field.md#field_class) instance representing the field at the given path. |
|
||||
| <b>function(pipeline, ...)</b> |
|
||||
| [execute(pipeline)](./firestore_pipelines.md#execute_01df620) | Executes a pipeline and returns a Promise to represent the asynchronous operation.<!-- -->The returned Promise can be used to track the progress of the pipeline execution and retrieve the results (or handle any errors) asynchronously.<!-- -->The pipeline results are returned as a [PipelineSnapshot](./firestore_pipelines.pipelinesnapshot.md#pipelinesnapshot_class) that contains a list of [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) objects. Each [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) typically represents a single key/value map that has passed through all the stages of the pipeline, however this might differ depending on the stages involved in the pipeline. For example:<ul> <li>If there are no stages or only transformation stages, each [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) represents a single document.</li> <li>If there is an aggregation, only a single [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) is returned, representing the aggregated results over the entire dataset .</li> <li>If there is an aggregation stage with grouping, each [PipelineResult](./firestore_pipelines.pipelineresult.md#pipelineresult_class) represents a distinct group and its associated aggregated values.</li> </ul> |
|
||||
| <b>function(rquery, ...)</b> |
|
||||
| [documentMatches(rquery)](./firestore_pipelines.md#documentmatches_d7a12c2) | <b><i>(Public Preview)</i></b> Perform a full-text search on all indexed search fields in the document. |
|
||||
| <b>function(stringExpression, ...)</b> |
|
||||
| [charLength(stringExpression)](./firestore_pipelines.md#charlength_c25a54a) | Creates an expression that calculates the character length of a string expression in UTF-8. |
|
||||
| [endsWith(stringExpression, suffix)](./firestore_pipelines.md#endswith_0a0b889) | Creates an expression that checks if a string expression ends with a given postfix. |
|
||||
@@ -442,7 +446,6 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [PipelineExecuteOptions](./firestore_pipelines.pipelineexecuteoptions.md#pipelineexecuteoptions_interface) | Options defining Pipeline execution. |
|
||||
| [Selectable](./firestore_pipelines.selectable.md#selectable_interface) | An interface that represents a selectable expression. |
|
||||
| [SnapshotOptions](./firestore_pipelines.snapshotoptions.md#snapshotoptions_interface) | Options that configure how data is retrieved from a <code>DocumentSnapshot</code> (for example the desired behavior for server timestamps that have not yet been set to their final value). |
|
||||
| [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) | Options defining how a Stage is evaluated. |
|
||||
|
||||
## Type Aliases
|
||||
|
||||
@@ -450,7 +453,7 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| --- | --- |
|
||||
| [AddFieldsStageOptions](./firestore_pipelines.md#addfieldsstageoptions) | Options defining how an AddFieldsStage is evaluated. See [Pipeline.addFields()](./firestore_pipelines.pipeline.md#pipelineaddfields)<!-- -->. |
|
||||
| [AggregateStageOptions](./firestore_pipelines.md#aggregatestageoptions) | Options defining how an AggregateStage is evaluated. See [Pipeline.aggregate()](./firestore_pipelines.pipeline.md#pipelineaggregate)<!-- -->. |
|
||||
| [CollectionGroupStageOptions](./firestore_pipelines.md#collectiongroupstageoptions) | Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) and provides specific settings for how a collection group is identified and processed during pipeline execution.<!-- -->See [PipelineSource.collectionGroup()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollectiongroup) to create a collection group stage. |
|
||||
| [CollectionGroupStageOptions](./firestore_pipelines.md#collectiongroupstageoptions) | Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.md#stageoptions) and provides specific settings for how a collection group is identified and processed during pipeline execution.<!-- -->See [PipelineSource.collectionGroup()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollectiongroup) to create a collection group stage. |
|
||||
| [CollectionStageOptions](./firestore_pipelines.md#collectionstageoptions) | Options defining how a CollectionStage is evaluated. See [PipelineSource.collection()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollection)<!-- -->. |
|
||||
| [DatabaseStageOptions](./firestore_pipelines.md#databasestageoptions) | Options defining how a DatabaseStage is evaluated. See [PipelineSource.database()](./firestore_pipelines.pipelinesource.md#pipelinesourcedatabase)<!-- -->. |
|
||||
| [DistinctStageOptions](./firestore_pipelines.md#distinctstageoptions) | Options defining how a DistinctStage is evaluated. See [Pipeline.distinct()](./firestore_pipelines.pipeline.md#pipelinedistinct)<!-- -->. |
|
||||
@@ -464,10 +467,12 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [Primitive](./firestore_pipelines.md#primitive) | Primitive types. |
|
||||
| [RemoveFieldsStageOptions](./firestore_pipelines.md#removefieldsstageoptions) | Options defining how a RemoveFieldsStage is evaluated. See [Pipeline.removeFields()](./firestore_pipelines.pipeline.md#pipelineremovefields)<!-- -->. |
|
||||
| [ReplaceWithStageOptions](./firestore_pipelines.md#replacewithstageoptions) | Options defining how a ReplaceWithStage is evaluated. See [Pipeline.replaceWith()](./firestore_pipelines.pipeline.md#pipelinereplacewith)<!-- -->. |
|
||||
| [SampleStageOptions](./firestore_pipelines.md#samplestageoptions) | Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) with a specific configuration where only one of the defined sampling methods can be applied.<!-- -->See [Pipeline.sample()](./firestore_pipelines.pipeline.md#pipelinesample) to create a sample stage.. |
|
||||
| [SampleStageOptions](./firestore_pipelines.md#samplestageoptions) | Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.md#stageoptions) with a specific configuration where only one of the defined sampling methods can be applied.<!-- -->See [Pipeline.sample()](./firestore_pipelines.pipeline.md#pipelinesample) to create a sample stage.. |
|
||||
| [SearchStageOptions](./firestore_pipelines.md#searchstageoptions) | <b><i>(Public Preview)</i></b> Options defining how a SearchStage is evaluated. See . |
|
||||
| [SelectStageOptions](./firestore_pipelines.md#selectstageoptions) | Options defining how a SelectStage is evaluated. See [Pipeline.select()](./firestore_pipelines.pipeline.md#pipelineselect)<!-- -->. |
|
||||
| [SetOptions](./firestore_pipelines.md#setoptions) | An options object that configures the behavior of [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->, and calls. These calls can be configured to perform granular merges instead of overwriting the target documents in their entirety by providing a <code>SetOptions</code> with <code>merge: true</code>. |
|
||||
| [SortStageOptions](./firestore_pipelines.md#sortstageoptions) | Options defining how a SortStage is evaluated. See [Pipeline.sort()](./firestore_pipelines.pipeline.md#pipelinesort)<!-- -->. |
|
||||
| [StageOptions](./firestore_pipelines.md#stageoptions) | Options defining how a Stage is evaluated. |
|
||||
| [TimeGranularity](./firestore_pipelines.md#timegranularity) | Specify time granularity for expressions. |
|
||||
| [TimePart](./firestore_pipelines.md#timepart) | Specify time parts for <code>timestampExtract</code> expressions. |
|
||||
| [TimeUnit](./firestore_pipelines.md#timeunit) | Specify time units for expressions. |
|
||||
@@ -551,6 +556,35 @@ rand();
|
||||
|
||||
```
|
||||
|
||||
### score() {:#score}
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Evaluates to the search score that reflects the topicality of the document to all of 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`<!-- -->.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function score(): Expression;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
[Expression](./firestore_pipelines.expression.md#expression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```typescript
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: 'waffles',
|
||||
sort: score().descending()
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## function(array, ...)
|
||||
|
||||
### arrayContains(array, element) {:#arraycontains_a00ea48}
|
||||
@@ -5797,6 +5831,43 @@ export declare function floor(fieldName: string): FunctionExpression;
|
||||
|
||||
A new [Expression](./firestore_pipelines.expression.md#expression_class) representing the floor of the numeric value.
|
||||
|
||||
### geoDistance(fieldName, location) {:#geodistance_ea237a8}
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Evaluates to the distance in meters between the location in the specified field and the query location.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function geoDistance(fieldName: string | Field, location: GeoPoint | Expression): Expression;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| fieldName | string \| [Field](./firestore_pipelines.field.md#field_class) | Specifies the field in the document which contains the first GeoPoint for distance computation. |
|
||||
| location | [GeoPoint](./firestore_.geopoint.md#geopoint_class) \| [Expression](./firestore_pipelines.expression.md#expression_class) | Compute distance to this GeoPoint. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Expression](./firestore_pipelines.expression.md#expression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```typescript
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: 'waffles',
|
||||
sort: geoDistance('location', new GeoPoint(37.0, -122.0)).ascending()
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### greaterThan(fieldName, expression) {:#greaterthan_1e91657}
|
||||
|
||||
Creates an expression that checks if a field's value is greater than an expression.
|
||||
@@ -9898,6 +9969,43 @@ const results: PipelineResult[] = snapshot.results;
|
||||
|
||||
```
|
||||
|
||||
## function(rquery, ...)
|
||||
|
||||
### documentMatches(rquery) {:#documentmatches_d7a12c2}
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Perform a full-text search on all indexed search fields in the document.
|
||||
|
||||
This Expression can only be used within a `Search` stage.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function documentMatches(rquery: string | Expression): BooleanExpression;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| rquery | string \| [Expression](./firestore_pipelines.expression.md#expression_class) | Define the search query using the search domain-specific language (DSL). |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[BooleanExpression](./firestore_pipelines.booleanexpression.md#booleanexpression_class)
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```typescript
|
||||
db.pipeline().collection('restaurants').search({
|
||||
query: documentMatches('waffles OR pancakes')
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## function(stringExpression, ...)
|
||||
|
||||
### charLength(stringExpression) {:#charlength_c25a54a}
|
||||
@@ -11549,7 +11657,7 @@ export declare type AggregateStageOptions = StageOptions & {
|
||||
|
||||
## CollectionGroupStageOptions
|
||||
|
||||
Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) and provides specific settings for how a collection group is identified and processed during pipeline execution.
|
||||
Defines the configuration options for a CollectionGroupStage within a pipeline. This type extends [StageOptions](./firestore_pipelines.md#stageoptions) and provides specific settings for how a collection group is identified and processed during pipeline execution.
|
||||
|
||||
See [PipelineSource.collectionGroup()](./firestore_pipelines.pipelinesource.md#pipelinesourcecollectiongroup) to create a collection group stage.
|
||||
|
||||
@@ -11732,7 +11840,7 @@ export declare type ReplaceWithStageOptions = StageOptions & {
|
||||
|
||||
## SampleStageOptions
|
||||
|
||||
Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.stageoptions.md#stageoptions_interface) with a specific configuration where only one of the defined sampling methods can be applied.
|
||||
Defines the options for evaluating a sample stage within a pipeline. This type combines common [StageOptions](./firestore_pipelines.md#stageoptions) with a specific configuration where only one of the defined sampling methods can be applied.
|
||||
|
||||
See [Pipeline.sample()](./firestore_pipelines.pipeline.md#pipelinesample) to create a sample stage..
|
||||
|
||||
@@ -11745,6 +11853,23 @@ export declare type SampleStageOptions = StageOptions & OneOf<{
|
||||
}>;
|
||||
```
|
||||
|
||||
## SearchStageOptions
|
||||
|
||||
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
|
||||
>
|
||||
|
||||
Options defining how a SearchStage is evaluated. See .
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type SearchStageOptions = StageOptions & {
|
||||
query: BooleanExpression | string;
|
||||
sort?: Ordering | Ordering[];
|
||||
addFields?: Selectable[];
|
||||
};
|
||||
```
|
||||
|
||||
## SelectStageOptions
|
||||
|
||||
Options defining how a SelectStage is evaluated. See [Pipeline.select()](./firestore_pipelines.pipeline.md#pipelineselect)<!-- -->.
|
||||
@@ -11783,6 +11908,20 @@ export declare type SortStageOptions = StageOptions & {
|
||||
};
|
||||
```
|
||||
|
||||
## StageOptions
|
||||
|
||||
Options defining how a Stage is evaluated.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type StageOptions = {
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## TimeGranularity
|
||||
|
||||
Specify time granularity for expressions.
|
||||
|
||||
@@ -55,6 +55,7 @@ distanceField: 'computedDistance' // optional
|
||||
| [replaceWith(options)](./firestore_pipelines.pipeline.md#pipelinereplacewith) | | |
|
||||
| [sample(documents)](./firestore_pipelines.pipeline.md#pipelinesample) | | Performs a pseudo-random sampling of the documents from the previous stage.<p>This stage will filter documents pseudo-randomly. The parameter specifies how number of documents to be returned.<p>Examples: |
|
||||
| [sample(options)](./firestore_pipelines.pipeline.md#pipelinesample) | | Performs a pseudo-random sampling of the documents from the previous stage.<p>This stage will filter documents pseudo-randomly. The 'options' parameter specifies how sampling will be performed. See [SampleStageOptions](./firestore_pipelines.md#samplestageoptions) for more information. |
|
||||
| [search(options)](./firestore_pipelines.pipeline.md#pipelinesearch) | | |
|
||||
| [select(selection, additionalSelections)](./firestore_pipelines.pipeline.md#pipelineselect) | | Selects or creates a set of fields from the outputs of previous stages.<p>The selected fields are defined using [Selectable](./firestore_pipelines.selectable.md#selectable_interface) expressions, which can be:<ul> <li><code>string</code> : Name of an existing field</li> <li>[Field](./firestore_pipelines.field.md#field_class)<!-- -->: References an existing field.</li> <li>[AliasedExpression](./firestore_pipelines.aliasedexpression.md#aliasedexpression_class)<!-- -->: Represents the result of a function with an assigned alias name using [Expression.as()](./firestore_pipelines.expression.md#expressionas)</li> </ul><p>If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields()](./firestore_pipelines.pipeline.md#pipelineaddfields) instead if only additions are desired.<p>Example: |
|
||||
| [select(options)](./firestore_pipelines.pipeline.md#pipelineselect) | | Selects or creates a set of fields from the outputs of previous stages.<p>The selected fields are defined using [Selectable](./firestore_pipelines.selectable.md#selectable_interface) expressions, which can be:<ul> <li><code>string</code>: Name of an existing field</li> <li>[Field](./firestore_pipelines.field.md#field_class)<!-- -->: References an existing field.</li> <li>[AliasedExpression](./firestore_pipelines.aliasedexpression.md#aliasedexpression_class)<!-- -->: Represents the result of a function with an assigned alias name using [Expression.as()](./firestore_pipelines.expression.md#expressionas)</li> </ul><p>If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields()](./firestore_pipelines.pipeline.md#pipelineaddfields) instead if only additions are desired.<p>Example: |
|
||||
| [sort(ordering, additionalOrderings)](./firestore_pipelines.pipeline.md#pipelinesort) | | Sorts the documents from previous stages based on one or more [Ordering](./firestore_pipelines.ordering.md#ordering_class) criteria.<p>This stage allows you to order the results of your pipeline. You can specify multiple [Ordering](./firestore_pipelines.ordering.md#ordering_class) instances to sort by multiple fields in ascending or descending order. If documents have the same value for a field used for sorting, the next specified ordering will be used. If all orderings result in equal comparison, the documents are considered equal and the order is unspecified.<p>Example: |
|
||||
@@ -708,6 +709,24 @@ firestore.pipeline().collection("books")
|
||||
|
||||
```
|
||||
|
||||
## Pipeline.search()
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
search(options: SearchStageOptions): Pipeline;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| options | [SearchStageOptions](./firestore_pipelines.md#searchstageoptions) | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Pipeline](./firestore_pipelines.pipeline.md#pipeline_class)
|
||||
|
||||
## Pipeline.select()
|
||||
|
||||
Selects or creates a set of fields from the outputs of previous stages.
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
Project: /docs/reference/js/_project.yaml
|
||||
Book: /docs/reference/_book.yaml
|
||||
page_type: reference
|
||||
|
||||
{% comment %}
|
||||
DO NOT EDIT THIS FILE!
|
||||
This is generated by the JS SDK team, and any local changes will be
|
||||
overwritten. Changes should be made in the source code at
|
||||
https://github.com/firebase/firebase-js-sdk
|
||||
{% endcomment %}
|
||||
|
||||
# StageOptions interface
|
||||
Options defining how a Stage is evaluated.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare interface StageOptions
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [rawOptions](./firestore_pipelines.stageoptions.md#stageoptionsrawoptions) | { \[name: string\]: unknown; } | An escape hatch to set options not known at SDK build time. These values will be passed directly to the Firestore backend and not used by the SDK.<!-- -->The option name will be used as provided. And must match the name format used by the backend (hint: use a snake\_case\_name).<!-- -->Raw option values can be any type supported by Firestore (for example: string, boolean, number, map, …). Value types not known to the SDK will be rejected.<!-- -->Values specified in rawOptions will take precedence over any options with the same name set by the SDK.<code>rawOptions</code> supports dot notation, if you want to override a nested option. |
|
||||
|
||||
## StageOptions.rawOptions
|
||||
|
||||
An escape hatch to set options not known at SDK build time. These values will be passed directly to the Firestore backend and not used by the SDK.
|
||||
|
||||
The option name will be used as provided. And must match the name format used by the backend (hint: use a snake\_case\_name).
|
||||
|
||||
Raw option values can be any type supported by Firestore (for example: string, boolean, number, map, …). Value types not known to the SDK will be rejected.
|
||||
|
||||
Values specified in rawOptions will take precedence over any options with the same name set by the SDK.
|
||||
|
||||
`rawOptions` supports dot notation, if you want to override a nested option.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
```
|
||||
@@ -80,7 +80,10 @@ export {
|
||||
SampleStageOptions,
|
||||
UnionStageOptions,
|
||||
UnnestStageOptions,
|
||||
SortStageOptions
|
||||
SortStageOptions,
|
||||
SearchStageOptions
|
||||
// TODO(search) export with backend support
|
||||
// QueryEnhancement
|
||||
} from '../../src/lite-api/stage_options';
|
||||
|
||||
export {
|
||||
@@ -216,6 +219,12 @@ export {
|
||||
split,
|
||||
timestampTruncate,
|
||||
timestampExtract,
|
||||
// snippet,
|
||||
// SnippetOptions,
|
||||
score,
|
||||
// matches,
|
||||
documentMatches,
|
||||
geoDistance,
|
||||
AliasedExpression,
|
||||
Field,
|
||||
Constant,
|
||||
|
||||
@@ -50,7 +50,10 @@ export {
|
||||
SampleStageOptions,
|
||||
UnionStageOptions,
|
||||
UnnestStageOptions,
|
||||
SortStageOptions
|
||||
SortStageOptions,
|
||||
SearchStageOptions
|
||||
// TODO(search) export with backend support
|
||||
// QueryEnhancement
|
||||
} from './lite-api/stage_options';
|
||||
|
||||
export {
|
||||
@@ -185,6 +188,13 @@ export {
|
||||
timestampTruncate,
|
||||
timestampExtract,
|
||||
split,
|
||||
score,
|
||||
documentMatches,
|
||||
geoDistance,
|
||||
// TODO(search) add with backend support
|
||||
// snippet,
|
||||
// SnippetOptions,
|
||||
// matches,
|
||||
Expression,
|
||||
AliasedExpression,
|
||||
Field,
|
||||
|
||||
@@ -17,11 +17,16 @@
|
||||
|
||||
import { FirestoreError } from '../api';
|
||||
import { ParseContext } from '../api/parse_context';
|
||||
import { OptionsUtil } from '../core/options_util';
|
||||
import {
|
||||
DOCUMENT_KEY_NAME,
|
||||
FieldPath as InternalFieldPath
|
||||
} from '../model/path';
|
||||
import { Value as ProtoValue } from '../protos/firestore_proto_api';
|
||||
import {
|
||||
ApiClientObjectMap,
|
||||
firestoreV1ApiClientInterfaces,
|
||||
Value as ProtoValue
|
||||
} from '../protos/firestore_proto_api';
|
||||
import {
|
||||
JsonProtoSerializer,
|
||||
ProtoValueSerializable,
|
||||
@@ -147,7 +152,6 @@ function fieldOrExpression(value: unknown): Expression {
|
||||
return valueToDefaultExpr(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents an expression that can be evaluated to a value within the execution of a {@link
|
||||
@@ -3286,6 +3290,85 @@ export abstract class Expression implements ProtoValueSerializable, UserData {
|
||||
return new FunctionExpression('timestamp_trunc', args);
|
||||
}
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * 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();
|
||||
// }
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * 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 domain-specific language (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: SnippetOptions): Expression;
|
||||
//
|
||||
// snippet(queryOrOptions: string | SnippetOptions): Expression {
|
||||
// const options: 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
|
||||
|
||||
/**
|
||||
@@ -3592,6 +3675,39 @@ export class Field extends Expression implements Selectable {
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * 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 search domain-specific language (DSL).
|
||||
// */
|
||||
// matches(rquery: string | Expression): BooleanExpression {
|
||||
// return new FunctionExpression(
|
||||
// 'matches',
|
||||
// [this, valueToDefaultExpr(rquery)],
|
||||
// 'matches'
|
||||
// ).asBoolean();
|
||||
// }
|
||||
|
||||
/**
|
||||
* @beta
|
||||
* 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)],
|
||||
'geoDistance'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
@@ -3880,30 +3996,81 @@ export class FunctionExpression extends Expression {
|
||||
readonly expressionType: ExpressionType = 'Function';
|
||||
|
||||
constructor(name: string, params: Expression[]);
|
||||
|
||||
/**
|
||||
* @hideconstructor
|
||||
*/
|
||||
constructor(
|
||||
name: string,
|
||||
params: Expression[],
|
||||
_methodName: string | undefined
|
||||
_methodName?: string,
|
||||
options?: {}
|
||||
);
|
||||
|
||||
/**
|
||||
* @hideconstructor
|
||||
*/
|
||||
constructor(
|
||||
private name: string,
|
||||
private params: Expression[],
|
||||
readonly _methodName?: string
|
||||
methodName?: string,
|
||||
options?: {}
|
||||
) {
|
||||
super();
|
||||
|
||||
if (methodName !== undefined) {
|
||||
this._methodName = methodName;
|
||||
}
|
||||
if (options !== undefined) {
|
||||
this._options = options;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
_methodName: string | undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
private _options: {} | undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
get _optionsUtil(): OptionsUtil {
|
||||
return new OptionsUtil({});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
_optionsProto:
|
||||
| ApiClientObjectMap<firestoreV1ApiClientInterfaces.Value>
|
||||
| undefined = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
_toProto(serializer: JsonProtoSerializer): ProtoValue {
|
||||
return {
|
||||
const returnValue: ProtoValue = {
|
||||
functionValue: {
|
||||
name: this.name,
|
||||
args: this.params.map(p => p._toProto(serializer))
|
||||
}
|
||||
};
|
||||
|
||||
if (this._optionsProto) {
|
||||
returnValue.functionValue!.options = this._optionsProto;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3917,6 +4084,12 @@ export class FunctionExpression extends Expression {
|
||||
this.params.forEach(expr => {
|
||||
return expr._readUserData(context);
|
||||
});
|
||||
if (this._options) {
|
||||
this._optionsProto = this._optionsUtil.getOptionsProto(
|
||||
context,
|
||||
this._options
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4105,6 +4278,37 @@ export class BooleanField extends BooleanExpression {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[], options?: {}) {
|
||||
super('snippet', params, 'snippet', options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an aggregation that counts the number of stage inputs where the provided
|
||||
* boolean expression evaluates to true.
|
||||
@@ -10899,6 +11103,275 @@ export function timestampExtract(
|
||||
);
|
||||
}
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * Perform a full-text search on the specified field.
|
||||
// *
|
||||
// * @remarks This Expression can only be used within a `Search` stage.
|
||||
// *
|
||||
// * @example
|
||||
// * ```typescript
|
||||
// * db.pipeline().collection('restaurants').search({
|
||||
// * query: matches('menu', 'waffles')
|
||||
// * })
|
||||
// * ```
|
||||
// *
|
||||
// * @param searchField Search the specified field.
|
||||
// * @param rquery Define the search query using the search domain-specific language (DSL).
|
||||
// */
|
||||
// export function matches(
|
||||
// searchField: string | Field,
|
||||
// rquery: string | Expression
|
||||
// ): BooleanExpression {
|
||||
// return toField(searchField).matches(rquery);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @beta
|
||||
* Perform a full-text search on all indexed search fields in the document.
|
||||
*
|
||||
* @remarks This Expression can only be used within a `Search` stage.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: documentMatches('waffles OR pancakes')
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @param rquery Define the search query using the search domain-specific language (DSL).
|
||||
*/
|
||||
export function documentMatches(
|
||||
rquery: string | Expression
|
||||
): BooleanExpression {
|
||||
return new FunctionExpression(
|
||||
'document_matches',
|
||||
[valueToDefaultExpr(rquery)],
|
||||
'documentMatches'
|
||||
).asBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @beta
|
||||
*
|
||||
* Evaluates to the search score that reflects the topicality of the document
|
||||
* to all of 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`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: 'waffles',
|
||||
* sort: score().descending()
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @remarks This Expression can only be used within a `Search` stage.
|
||||
*/
|
||||
export function score(): Expression {
|
||||
return new FunctionExpression('score', [], 'score');
|
||||
}
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * Options defining how a snippet expression is evaluated.
|
||||
// */
|
||||
// export interface SnippetOptions {
|
||||
// /**
|
||||
// * Define the search query using the search domain-specific language (DSL).
|
||||
// */
|
||||
// rquery: string;
|
||||
//
|
||||
// /**
|
||||
// * The maximum width of the string estimated for a variable width font. The
|
||||
// * unit is tenths of ems. The default is `160`.
|
||||
// */
|
||||
// maxSnippetWidth?: number;
|
||||
//
|
||||
// /**
|
||||
// * The maximum number of non-contiguous pieces of text in the returned snippet.
|
||||
// * The default is `1`.
|
||||
// */
|
||||
// maxSnippets?: number;
|
||||
//
|
||||
// /**
|
||||
// * The string to join the pieces. The default value is '\n'
|
||||
// */
|
||||
// separator?: string;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 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.
|
||||
// *
|
||||
// * @example
|
||||
// * ```typescript
|
||||
// * db.pipeline().collection('restaurants').search({
|
||||
// * query: 'waffles',
|
||||
// * addFields: { snippet: snippet('menu', 'waffles') }
|
||||
// * })
|
||||
// * ```
|
||||
// *
|
||||
// * @param searchField Search the specified field for matching terms.
|
||||
// * @param rquery Define the search query using the search domain-specific language (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 domain-specific language (DSL).
|
||||
// */
|
||||
// export function snippet(
|
||||
// searchField: string | Field,
|
||||
// options: SnippetOptions
|
||||
// ): Expression;
|
||||
// export function snippet(
|
||||
// field: string | Field,
|
||||
// queryOrOptions: string | SnippetOptions
|
||||
// ): Expression {
|
||||
// return toField(field).snippet(
|
||||
// isString(queryOrOptions) ? { rquery: queryOrOptions } : queryOrOptions
|
||||
// );
|
||||
// }
|
||||
|
||||
/**
|
||||
* @beta
|
||||
* 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.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: 'waffles',
|
||||
* sort: geoDistance('location', new GeoPoint(37.0, -122.0)).ascending()
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * 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
|
||||
|
||||
/**
|
||||
@@ -11018,8 +11491,10 @@ export function isSelectable(val: unknown): val is Selectable {
|
||||
}
|
||||
|
||||
export function isOrdering(val: unknown): val is Ordering {
|
||||
const candidate = val as Ordering;
|
||||
const candidate = val as Ordering | undefined;
|
||||
return (
|
||||
candidate !== undefined &&
|
||||
candidate !== null &&
|
||||
isExpr(candidate.expr) &&
|
||||
(candidate.direction === 'ascending' ||
|
||||
candidate.direction === 'descending')
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
aliasedAggregateToMap,
|
||||
fieldOrExpression,
|
||||
selectablesToMap,
|
||||
selectablesToObject,
|
||||
vectorToExpr
|
||||
} from '../util/pipeline_util';
|
||||
import { isNumber, isString } from '../util/types';
|
||||
@@ -49,7 +50,8 @@ import {
|
||||
isAliasedAggregate,
|
||||
toField,
|
||||
isOrdering,
|
||||
isExpr
|
||||
isExpr,
|
||||
documentMatches
|
||||
} from './expressions';
|
||||
import {
|
||||
AddFields,
|
||||
@@ -67,7 +69,8 @@ import {
|
||||
Stage,
|
||||
Union,
|
||||
Unnest,
|
||||
Where
|
||||
Where,
|
||||
Search
|
||||
} from './stage';
|
||||
import {
|
||||
AddFieldsStageOptions,
|
||||
@@ -79,6 +82,7 @@ import {
|
||||
RemoveFieldsStageOptions,
|
||||
ReplaceWithStageOptions,
|
||||
SampleStageOptions,
|
||||
SearchStageOptions,
|
||||
SelectStageOptions,
|
||||
SortStageOptions,
|
||||
StageOptions,
|
||||
@@ -840,6 +844,80 @@ export class Pipeline implements ProtoSerializable<ProtoPipeline>, UserData {
|
||||
return this._addStage(stage);
|
||||
}
|
||||
|
||||
// TODO(search) link to external documentation citing list of supported
|
||||
// expressions, when that documentation is created. List is not maintained
|
||||
// in the SDK because the list will change as the backend enables support.
|
||||
/**
|
||||
* @beta
|
||||
* Add a search stage to the Pipeline. The search stage supports
|
||||
* full-text search and geo search expressions.
|
||||
*
|
||||
* @remarks This must be the first stage of the pipeline.
|
||||
* @remarks A limited set of expressions are supported in the search stage.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Full-text search example
|
||||
* firestore.pipeline().collection("restaurants")
|
||||
* .search({
|
||||
* query: documentMatches("waffles OR pancakes"),
|
||||
* sort: [
|
||||
* score().descending(),
|
||||
* ],
|
||||
* addFields: [
|
||||
* score().as("searchScore"),
|
||||
* ]
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Geo distance search example
|
||||
* const queryLocation = new GeoPoint(0, 0);
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: field('location').geoDistance(queryLocation).lessThanOrEqual(1000),
|
||||
* sort: [
|
||||
* score().descending(),
|
||||
* ],
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @param options - An object that specifies parameters for the stage.
|
||||
* @return A new `Pipeline` object with this stage appended to the stage list.
|
||||
*/
|
||||
search(options: SearchStageOptions): Pipeline {
|
||||
// Convert user land convenience types to internal types
|
||||
const addFields: Record<string, Expression> | undefined = options.addFields
|
||||
? selectablesToObject(options.addFields)
|
||||
: undefined;
|
||||
const query: BooleanExpression = isExpr(options.query)
|
||||
? options.query
|
||||
: documentMatches(options.query);
|
||||
const sort: Ordering[] | undefined = isOrdering(options.sort)
|
||||
? [options.sort]
|
||||
: options.sort;
|
||||
|
||||
const select: Record<string, Expression> | undefined = undefined;
|
||||
// TODO(search) enable with backend support
|
||||
// select = options.select
|
||||
// ? selectablesToObject(options.select)
|
||||
// : undefined;
|
||||
|
||||
const internalOptions = {
|
||||
...options,
|
||||
addFields,
|
||||
select,
|
||||
query,
|
||||
sort
|
||||
};
|
||||
|
||||
// Create stage object
|
||||
const stage = new Search(internalOptions);
|
||||
|
||||
// Add stage to the pipeline
|
||||
return this._addStage(stage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the documents from previous stages based on one or more {@link @firebase/firestore/pipelines#Ordering} criteria.
|
||||
*
|
||||
|
||||
@@ -41,12 +41,12 @@ import {
|
||||
Ordering
|
||||
} from './expressions';
|
||||
import { Pipeline } from './pipeline';
|
||||
import { StageOptions } from './stage_options';
|
||||
import { QueryEnhancement, StageOptions } from './stage_options';
|
||||
import { isUserData, UserData } from './user_data_reader';
|
||||
|
||||
export abstract class Stage implements ProtoSerializable<ProtoStage>, UserData {
|
||||
/**
|
||||
* Store optionsProto parsed by _readUserData.
|
||||
* Store _optionsProto parsed by _readUserData.
|
||||
* @private
|
||||
* @internal
|
||||
* @protected
|
||||
@@ -57,7 +57,7 @@ export abstract class Stage implements ProtoSerializable<ProtoStage>, UserData {
|
||||
protected knownOptions: Record<string, unknown>;
|
||||
protected rawOptions?: Record<string, unknown>;
|
||||
|
||||
constructor(options: StageOptions) {
|
||||
constructor(options: Record<string, unknown> & StageOptions) {
|
||||
({ rawOptions: this.rawOptions, ...this.knownOptions } = options);
|
||||
}
|
||||
|
||||
@@ -645,6 +645,96 @@ export class Replace extends Stage {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line -- eslint should not convert this type to an interface
|
||||
type InternalSearchOptions = {
|
||||
// These are constrained from the public type
|
||||
query: BooleanExpression;
|
||||
sort?: Ordering[];
|
||||
select?: Record<string, Expression>;
|
||||
addFields?: Record<string, Expression>;
|
||||
|
||||
// These are the same as the public type
|
||||
languageCode?: string;
|
||||
retrievalDepth?: number;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
queryEnhancement?: QueryEnhancement;
|
||||
};
|
||||
|
||||
/**
|
||||
* @beta
|
||||
*/
|
||||
export class Search extends Stage {
|
||||
constructor(private _searchOptions: InternalSearchOptions) {
|
||||
super(_searchOptions);
|
||||
}
|
||||
|
||||
get _name(): string {
|
||||
return 'search';
|
||||
}
|
||||
|
||||
get _optionsUtil(): OptionsUtil {
|
||||
return new OptionsUtil({
|
||||
query: {
|
||||
serverName: 'query'
|
||||
},
|
||||
limit: {
|
||||
serverName: 'limit'
|
||||
},
|
||||
retrievalDepth: {
|
||||
serverName: 'retrieval_depth'
|
||||
},
|
||||
sort: {
|
||||
serverName: 'sort'
|
||||
},
|
||||
addFields: {
|
||||
serverName: 'add_fields'
|
||||
},
|
||||
select: {
|
||||
serverName: 'select'
|
||||
},
|
||||
offset: {
|
||||
serverName: 'offset'
|
||||
},
|
||||
queryEnhancement: {
|
||||
serverName: 'query_enhancement'
|
||||
},
|
||||
languageCode: {
|
||||
serverName: 'language_code'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
_toProto(serializer: JsonProtoSerializer): ProtoStage {
|
||||
return {
|
||||
...super._toProto(serializer),
|
||||
args: []
|
||||
};
|
||||
}
|
||||
|
||||
_readUserData(context: ParseContext): void {
|
||||
readUserDataHelper(this._searchOptions.query, context);
|
||||
if (this._searchOptions.addFields) {
|
||||
readUserDataHelper(this._searchOptions.addFields, context);
|
||||
}
|
||||
if (this._searchOptions.select) {
|
||||
readUserDataHelper(this._searchOptions.select, context);
|
||||
}
|
||||
if (this._searchOptions.sort) {
|
||||
readUserDataHelper(this._searchOptions.sort, context);
|
||||
}
|
||||
|
||||
super._readUserData(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @beta
|
||||
*/
|
||||
export class RawStage extends Stage {
|
||||
/**
|
||||
* @private
|
||||
@@ -692,14 +782,22 @@ export class RawStage extends Stage {
|
||||
* @private
|
||||
*/
|
||||
function readUserDataHelper<
|
||||
T extends Map<string, UserData> | UserData[] | UserData
|
||||
T extends
|
||||
| Map<string, UserData>
|
||||
| Record<string, UserData>
|
||||
| UserData[]
|
||||
| UserData
|
||||
>(expressionMap: T, context: ParseContext): T {
|
||||
if (isUserData(expressionMap)) {
|
||||
expressionMap._readUserData(context);
|
||||
} else if (Array.isArray(expressionMap)) {
|
||||
expressionMap.forEach(readableData => readableData._readUserData(context));
|
||||
} else {
|
||||
} else if (expressionMap instanceof Map) {
|
||||
expressionMap.forEach(expr => expr._readUserData(context));
|
||||
} else {
|
||||
Object.values(expressionMap).forEach(expression =>
|
||||
expression._readUserData(context)
|
||||
);
|
||||
}
|
||||
return expressionMap;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ import { VectorValue } from './vector_value';
|
||||
/**
|
||||
* Options defining how a Stage is evaluated.
|
||||
*/
|
||||
export interface StageOptions {
|
||||
// eslint-disable-next-line -- eslint should not convert this type to an interface
|
||||
export type StageOptions = {
|
||||
/**
|
||||
* An escape hatch to set options not known at SDK build time. These values
|
||||
* will be passed directly to the Firestore backend and not used by the SDK.
|
||||
@@ -53,7 +54,7 @@ export interface StageOptions {
|
||||
rawOptions?: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Options defining how a CollectionStage is evaluated. See {@link @firebase/firestore/pipelines#PipelineSource.(collection:1)}.
|
||||
*/
|
||||
@@ -226,6 +227,117 @@ export type FindNearestStageOptions = StageOptions & {
|
||||
*/
|
||||
distanceField?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @beta
|
||||
*
|
||||
* Specifies if the `matches` and `snippet` expressions will enhance the user
|
||||
* provided query to perform matching of synonyms, misspellings, lemmatization,
|
||||
* stemming.
|
||||
*
|
||||
* required - search will fail if the query enhancement times out or if the query
|
||||
* enhancement is not supported by the project's DRZ compliance
|
||||
* requirements.
|
||||
* preferred - search will fall back to the un-enhanced, user provided query, if
|
||||
* the query enhancement fails.
|
||||
*/
|
||||
export type QueryEnhancement = 'disabled' | 'required' | 'preferred';
|
||||
|
||||
/**
|
||||
* @beta
|
||||
* Options defining how a SearchStage is evaluated. See {@link @firebase/firestore/pipelines#Pipeline.(search)}.
|
||||
*/
|
||||
export type SearchStageOptions = StageOptions & {
|
||||
/**
|
||||
* Specifies the search query that will be used to query and score documents
|
||||
* by the search stage.
|
||||
*
|
||||
* The query can be expressed as an `Expression`, which will be used to score
|
||||
* and filter the results. Not all expressions supported by Pipelines
|
||||
* are supported in the Search query.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: or(
|
||||
* documentMatches("breakfast"),
|
||||
* field('menu').matches('waffle AND coffee')
|
||||
* )
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* The query can also be expressed as a string in the Search domain-specific language (DSL):
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: 'menu:(waffle and coffee) OR breakfast'
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* The query can also represent a geoDistance query:
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* db.pipeline().collection('restaurants').search({
|
||||
* query: field('location').geoDistance(new GeoPoint(0, 0)).lessThanOrEqual(1000)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
query: BooleanExpression | string;
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * The BCP-47 language code of text in the search query, such as, “en-US” or “sr-Latn”
|
||||
// */
|
||||
// languageCode?: string;
|
||||
|
||||
// TODO(search) add indexPartition after languageCode
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * The maximum number of documents to retrieve. Documents will be retrieved in the
|
||||
// * pre-sort order specified by the search index.
|
||||
// */
|
||||
// retrievalDepth?: number;
|
||||
|
||||
/**
|
||||
* Orderings specify how the returned documents are sorted.
|
||||
* One or more ordering are required.
|
||||
*/
|
||||
sort?: Ordering | Ordering[];
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * The number of documents to skip from the beginning of the search result set.
|
||||
// */
|
||||
// offset?: number;
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * The maximum number of documents to return from the Search stage.
|
||||
// */
|
||||
// limit?: number;
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * The fields to keep or add to each document,
|
||||
// * specified as an array of {@link @firebase/firestore/pipelines#Selectable}.
|
||||
// */
|
||||
// select?: Array<Selectable | string>;
|
||||
|
||||
/**
|
||||
* The fields to add to each document, specified as a {@link @firebase/firestore/pipelines#Selectable}.
|
||||
*/
|
||||
addFields?: Selectable[];
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// /**
|
||||
// * Define the query expansion behavior used by full-text search expressions
|
||||
// * in this search stage.
|
||||
// */
|
||||
// queryEnhancement?: QueryEnhancement;
|
||||
};
|
||||
/**
|
||||
* Options defining how a ReplaceWithStage is evaluated. See {@link @firebase/firestore/pipelines#Pipeline.(replaceWith:1)}.
|
||||
*/
|
||||
|
||||
@@ -36,10 +36,20 @@ import { isPlainObject } from './input_validation';
|
||||
import { isFirestoreValue } from './proto';
|
||||
import { isString } from './types';
|
||||
|
||||
/**
|
||||
* @deprecated use selectablesToObject instead
|
||||
* @param selectables
|
||||
*/
|
||||
export function selectablesToMap(
|
||||
selectables: Array<Selectable | string>
|
||||
): Map<string, Expression> {
|
||||
const result = new Map<string, Expression>();
|
||||
return new Map(Object.entries(selectablesToObject(selectables)));
|
||||
}
|
||||
|
||||
export function selectablesToObject(
|
||||
selectables: Array<Selectable | string>
|
||||
): Record<string, Expression> {
|
||||
const result: Record<string, Expression> = {};
|
||||
for (const selectable of selectables) {
|
||||
let alias: string;
|
||||
let expression: Expression;
|
||||
@@ -56,14 +66,14 @@ export function selectablesToMap(
|
||||
fail(0x5319, '`selectable` has an unsupported type', { selectable });
|
||||
}
|
||||
|
||||
if (result.get(alias) !== undefined) {
|
||||
if (result[alias] !== undefined) {
|
||||
throw new FirestoreError(
|
||||
'invalid-argument',
|
||||
`Duplicate alias or field '${alias}'`
|
||||
);
|
||||
}
|
||||
|
||||
result.set(alias, expression);
|
||||
result[alias] = expression;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ import { PrivateSettings } from './firebase_export';
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
declare const __karma__: any;
|
||||
|
||||
enum TargetBackend {
|
||||
export enum TargetBackend {
|
||||
EMULATOR = 'emulator',
|
||||
QA = 'qa',
|
||||
NIGHTLY = 'nightly',
|
||||
@@ -37,8 +37,6 @@ const PROJECT_CONFIG = require('../../../../../config/project.json');
|
||||
|
||||
export const TARGET_DB_ID: string | '(default)' = getTargetDbId();
|
||||
|
||||
export const RUN_ENTERPRISE_TESTS: boolean = getRunEnterpriseTests();
|
||||
|
||||
const TARGET_BACKEND: TargetBackend = getTargetBackend();
|
||||
|
||||
export const USE_EMULATOR: boolean = TARGET_BACKEND === TargetBackend.EMULATOR;
|
||||
@@ -64,7 +62,7 @@ function getTargetDbId(): string | '(default)' {
|
||||
return '(default)';
|
||||
}
|
||||
|
||||
function getRunEnterpriseTests(): boolean {
|
||||
export function getRunEnterpriseTests(): boolean {
|
||||
const karma = typeof __karma__ !== 'undefined' ? __karma__ : undefined;
|
||||
if (karma && karma.config.firestoreEdition === 'enterprise') {
|
||||
return true;
|
||||
@@ -89,7 +87,7 @@ function parseTargetBackend(targetBackend: string): TargetBackend {
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetBackend(): TargetBackend {
|
||||
export function getTargetBackend(): TargetBackend {
|
||||
const karma = typeof __karma__ !== 'undefined' ? __karma__ : undefined;
|
||||
if (karma && karma.config.targetBackend) {
|
||||
return parseTargetBackend(karma.config.targetBackend);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable camelcase -- use consistent field names for the search tests */
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { FirebaseError } from '@firebase/util';
|
||||
import { expect, use } from 'chai';
|
||||
@@ -41,15 +43,25 @@ import {
|
||||
doc,
|
||||
DocumentReference
|
||||
} from '../../src/lite-api/reference';
|
||||
import { addDoc, setDoc, deleteDoc } from '../../src/lite-api/reference_impl';
|
||||
import {
|
||||
addDoc,
|
||||
setDoc,
|
||||
deleteDoc,
|
||||
getDocs
|
||||
} from '../../src/lite-api/reference_impl';
|
||||
import { FindNearestStageOptions } from '../../src/lite-api/stage_options';
|
||||
import { Timestamp } from '../../src/lite-api/timestamp';
|
||||
import { writeBatch } from '../../src/lite-api/write_batch';
|
||||
import {
|
||||
getRunEnterpriseTests,
|
||||
getTargetBackend,
|
||||
TargetBackend
|
||||
} from '../integration/util/settings';
|
||||
import { addEqualityMatcher } from '../util/equality_matcher';
|
||||
import { describe } from '../util/mocha_extensions';
|
||||
import { Deferred } from '../util/promise';
|
||||
|
||||
import { withTestCollection } from './helpers';
|
||||
import { withTestCollection, withTestDb } from './helpers';
|
||||
import {
|
||||
field,
|
||||
and,
|
||||
@@ -180,60 +192,64 @@ import {
|
||||
arrayIndexOf,
|
||||
arrayIndexOfAll,
|
||||
arrayLastIndexOf,
|
||||
ifNull
|
||||
ifNull,
|
||||
documentMatches,
|
||||
score
|
||||
} from './pipeline_export';
|
||||
|
||||
use(chaiAsPromised);
|
||||
|
||||
const timestampDeltaMS = 10000;
|
||||
|
||||
let beginDocCreation: number = 0;
|
||||
let endDocCreation: number = 0;
|
||||
|
||||
async function testCollectionWithDocs(
|
||||
collection: CollectionReference,
|
||||
docs: { [id: string]: DocumentData }
|
||||
): Promise<CollectionReference<DocumentData>> {
|
||||
beginDocCreation = new Date().valueOf();
|
||||
for (const id in docs) {
|
||||
if (docs.hasOwnProperty(id)) {
|
||||
const ref = doc(collection, id);
|
||||
await setDoc(ref, docs[id]);
|
||||
}
|
||||
}
|
||||
endDocCreation = new Date().valueOf();
|
||||
return collection;
|
||||
}
|
||||
|
||||
function expectResults(snapshot: PipelineSnapshot, ...docs: string[]): void;
|
||||
function expectResults(
|
||||
snapshot: PipelineSnapshot,
|
||||
...data: DocumentData[]
|
||||
): void;
|
||||
|
||||
function expectResults(
|
||||
snapshot: PipelineSnapshot,
|
||||
...data: DocumentData[] | string[]
|
||||
): void {
|
||||
const docs = snapshot.results;
|
||||
|
||||
expect(docs.length).to.equal(data.length);
|
||||
|
||||
if (data.length > 0) {
|
||||
if (typeof data[0] === 'string') {
|
||||
const actualIds = docs.map(doc => doc.id);
|
||||
expect(actualIds).to.deep.equal(data);
|
||||
} else {
|
||||
docs.forEach(r => {
|
||||
expect(r.data()).to.deep.equal(data.shift());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe.skipClassic('Firestore Pipelines', () => {
|
||||
addEqualityMatcher();
|
||||
|
||||
let firestore: Firestore;
|
||||
let randomCol: CollectionReference;
|
||||
let beginDocCreation: number = 0;
|
||||
let endDocCreation: number = 0;
|
||||
|
||||
async function testCollectionWithDocs(docs: {
|
||||
[id: string]: DocumentData;
|
||||
}): Promise<CollectionReference<DocumentData>> {
|
||||
beginDocCreation = new Date().valueOf();
|
||||
for (const id in docs) {
|
||||
if (docs.hasOwnProperty(id)) {
|
||||
const ref = doc(randomCol, id);
|
||||
await setDoc(ref, docs[id]);
|
||||
}
|
||||
}
|
||||
endDocCreation = new Date().valueOf();
|
||||
return randomCol;
|
||||
}
|
||||
|
||||
function expectResults(snapshot: PipelineSnapshot, ...docs: string[]): void;
|
||||
function expectResults(
|
||||
snapshot: PipelineSnapshot,
|
||||
...data: DocumentData[]
|
||||
): void;
|
||||
|
||||
function expectResults(
|
||||
snapshot: PipelineSnapshot,
|
||||
...data: DocumentData[] | string[]
|
||||
): void {
|
||||
const docs = snapshot.results;
|
||||
|
||||
expect(docs.length).to.equal(data.length);
|
||||
|
||||
if (data.length > 0) {
|
||||
if (typeof data[0] === 'string') {
|
||||
const actualIds = docs.map(doc => doc.id);
|
||||
expect(actualIds).to.deep.equal(data);
|
||||
} else {
|
||||
docs.forEach(r => {
|
||||
expect(r.data()).to.deep.equal(data.shift());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function setupBookDocs(): Promise<CollectionReference<DocumentData>> {
|
||||
const bookDocs: { [id: string]: DocumentData } = {
|
||||
@@ -345,7 +361,7 @@ describe.skipClassic('Firestore Pipelines', () => {
|
||||
embedding: vector([1, 1, 1, 1, 1, 1, 1, 1, 1, 10])
|
||||
}
|
||||
};
|
||||
return testCollectionWithDocs(bookDocs);
|
||||
return testCollectionWithDocs(randomCol, bookDocs);
|
||||
}
|
||||
|
||||
let testDeferred: Deferred<void> | undefined;
|
||||
@@ -5679,3 +5695,655 @@ describe.skipClassic('Firestore Pipelines', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
(getRunEnterpriseTests() && getTargetBackend() === TargetBackend.NIGHTLY
|
||||
? describe
|
||||
: /* eslint-disable-next-line -- okay to skip tests */
|
||||
describe.skip)('Pipeline search', () => {
|
||||
addEqualityMatcher();
|
||||
let firestore: Firestore;
|
||||
let restaurantsCollection: CollectionReference;
|
||||
|
||||
const COLLECTION_NAME = 'TextSearchIntegrationTests';
|
||||
|
||||
async function setupRestaurantDocs(
|
||||
collection: CollectionReference
|
||||
): Promise<CollectionReference<DocumentData>> {
|
||||
const restaurantDocs: { [id: string]: DocumentData } = {
|
||||
sunnySideUp: {
|
||||
name: 'The Sunny Side Up',
|
||||
description:
|
||||
'A cozy neighborhood diner serving classic breakfast favorites all day long, from fluffy pancakes to savory omelets.',
|
||||
location: new GeoPoint(39.7541, -105.0002),
|
||||
menu: '<h3>Breakfast Classics</h3><ul><li>Denver Omelet - $12</li><li>Buttermilk Pancakes - $10</li><li>Steak and Eggs - $16</li></ul><h3>Sides</h3><ul><li>Hash Browns - $4</li><li>Thick-cut Bacon - $5</li><li>Drip Coffee - $2</li></ul>',
|
||||
average_price_per_person: 15
|
||||
},
|
||||
goldenWaffle: {
|
||||
name: 'The Golden Waffle',
|
||||
description:
|
||||
'Specializing exclusively in Belgian-style waffles. Open daily from 6:00 AM to 11:00 AM.',
|
||||
location: new GeoPoint(39.7183, -104.9621),
|
||||
menu: '<h3>Signature Waffles</h3><ul><li>Strawberry Delight - $11</li><li>Chicken and Waffles - $14</li><li>Chocolate Chip Crunch - $10</li></ul><h3>Drinks</h3><ul><li>Fresh OJ - $4</li><li>Artisan Coffee - $3</li></ul>',
|
||||
average_price_per_person: 13
|
||||
},
|
||||
lotusBlossomThai: {
|
||||
name: 'Lotus Blossom Thai',
|
||||
description:
|
||||
'Authentic Thai cuisine featuring hand-crushed spices and traditional family recipes from the Chiang Mai region.',
|
||||
location: new GeoPoint(39.7315, -104.9847),
|
||||
menu: '<h3>Appetizers</h3><ul><li>Spring Rolls - $7</li><li>Chicken Satay - $9</li></ul><h3>Main Course</h3><ul><li>Pad Thai - $15</li><li>Green Curry - $16</li><li>Drunken Noodles - $15</li></ul>',
|
||||
average_price_per_person: 22
|
||||
},
|
||||
mileHighCatch: {
|
||||
name: 'Mile High Catch',
|
||||
description:
|
||||
'Freshly sourced seafood offering a wide variety of Pacific fish and Atlantic shellfish in an upscale atmosphere.',
|
||||
location: new GeoPoint(39.7401, -104.9903),
|
||||
menu: '<h3>From the Raw Bar</h3><ul><li>Oysters (Half Dozen) - $18</li><li>Lobster Cocktail - $22</li></ul><h3>Entrees</h3><ul><li>Pan-Seared Salmon - $28</li><li>King Crab Legs - $45</li><li>Fish and Chips - $19</li></ul>',
|
||||
average_price_per_person: 45
|
||||
},
|
||||
peakBurgers: {
|
||||
name: 'Peak Burgers',
|
||||
description:
|
||||
'Casual burger joint focused on locally sourced Colorado beef and hand-cut fries.',
|
||||
location: new GeoPoint(39.7622, -105.0125),
|
||||
menu: '<h3>Burgers</h3><ul><li>The Peak Double - $12</li><li>Bison Burger - $15</li><li>Veggie Stack - $11</li></ul><h3>Sides</h3><ul><li>Truffle Fries - $6</li><li>Onion Rings - $5</li></ul>',
|
||||
average_price_per_person: 18
|
||||
},
|
||||
solTacos: {
|
||||
name: 'El Sol Tacos',
|
||||
description:
|
||||
'A vibrant street-side taco stand serving up quick, delicious, and traditional Mexican street food.',
|
||||
location: new GeoPoint(39.6952, -105.0274),
|
||||
menu: '<h3>Tacos ($3.50 each)</h3><ul><li>Al Pastor</li><li>Carne Asada</li><li>Pollo Asado</li><li>Nopales (Cactus)</li></ul><h3>Beverages</h3><ul><li>Horchata - $4</li><li>Mexican Coke - $3</li></ul>',
|
||||
average_price_per_person: 12
|
||||
},
|
||||
eastsideTacos: {
|
||||
name: 'Eastside Cantina',
|
||||
description:
|
||||
'Authentic street tacos and hand-shaken margaritas on the vibrant east side of the city.',
|
||||
location: new GeoPoint(39.735, -104.885),
|
||||
menu: '<h3>Tacos</h3><ul><li>Carnitas Tacos - $4</li><li>Barbacoa Tacos - $4.50</li><li>Shrimp Tacos - $5</li></ul><h3>Drinks</h3><ul><li>House Margarita - $9</li><li>Jarritos - $3</li></ul>',
|
||||
average_price_per_person: 18
|
||||
},
|
||||
eastsideChicken: {
|
||||
name: 'Eastside Chicken',
|
||||
description: 'Fried chicken to go - next to Eastside Cantina.',
|
||||
location: new GeoPoint(39.735, -104.885),
|
||||
menu: '<h3>Fried Chicken</h3><ul><li>Drumstick - $4</li><li>Wings - $1</li><li>Sandwich - $9</li></ul><h3>Drinks</h3><ul><li>House Margarita - $9</li><li>Jarritos - $3</li></ul>',
|
||||
average_price_per_person: 12
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(search) - Migrate this over to IndexTestHelper when search supports the equal filter.
|
||||
// Remove any restaurant docs not in the expected set - perhaps these were
|
||||
// set by another dev or test suite. This has potential to cause flakes in another concurrent
|
||||
// run of these tests, if they have added new test docs.
|
||||
const collectionSnapshot = await getDocs(collection);
|
||||
const expectedDocIds = Object.keys(restaurantDocs);
|
||||
const deletes = collectionSnapshot.docs
|
||||
.filter(ds => expectedDocIds.indexOf(ds.id) < 0)
|
||||
.map(ds => deleteDoc(ds.ref));
|
||||
await Promise.all(deletes);
|
||||
|
||||
// Add/overwrite all restaurant docs
|
||||
return testCollectionWithDocs(collection, restaurantDocs);
|
||||
}
|
||||
|
||||
// Resolves in `after` indicating the test suite has finished.
|
||||
// The function passed to withTestDbsPromise will await this promise,
|
||||
// meaning the firestore instance created by withTestDbsSettings will
|
||||
// not be disposed until this is resolved (after the test suite finished).
|
||||
let testSuiteDeferred: Deferred<void> | undefined;
|
||||
|
||||
// Resolves when withTestDbsPromise resolves, indicating that the
|
||||
// resources this method created have been disposed and the next test suite
|
||||
// can begin.
|
||||
let withTestDbsPromise: Promise<unknown> | undefined;
|
||||
|
||||
// Search tests will use restaurant docs
|
||||
before(async () => {
|
||||
// TODO(search) - Migrate this over to IndexTestHelper when search supports the equal filter.
|
||||
// Note: using a static collection of documents for every search test has an inherent risk
|
||||
// of flakiness. Search requires an index on the collection, which is the reason we use a pre-defined
|
||||
// collection. We cannot use the IndexTestHelper because that relies on an equality match to the testID
|
||||
// field. Search currently does not support the equal expression.
|
||||
|
||||
const setupDeferred = new Deferred<void>();
|
||||
testSuiteDeferred = new Deferred<void>();
|
||||
withTestDbsPromise = withTestDb(async firestoreInstance => {
|
||||
firestore = firestoreInstance;
|
||||
restaurantsCollection = collection(firestore, 'SearchIntegrationTests');
|
||||
await setupRestaurantDocs(restaurantsCollection);
|
||||
setupDeferred.resolve();
|
||||
|
||||
return testSuiteDeferred?.promise;
|
||||
});
|
||||
|
||||
await setupDeferred.promise;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
testSuiteDeferred?.resolve();
|
||||
await withTestDbsPromise;
|
||||
});
|
||||
|
||||
describe('search stage', () => {
|
||||
describe('DISABLE query expansion', () => {
|
||||
describe('query', () => {
|
||||
// TODO(search) enable with backend support
|
||||
// it('all search features', async () => {
|
||||
// const queryLocation = new GeoPoint(0, 0);
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: and(
|
||||
// documentMatches('waffles'),
|
||||
// field('description').matches('breakfast'),
|
||||
// field('location').geoDistance(queryLocation).lessThan(1000),
|
||||
// field('avgPrice').between(10, 20)
|
||||
// ),
|
||||
// select: [
|
||||
// field('title'),
|
||||
// field('menu'),
|
||||
// field('description'),
|
||||
// field('location').geoDistance(queryLocation).as('distance')
|
||||
// ],
|
||||
// addFields: [score().as('searchScore')],
|
||||
// offset: 0,
|
||||
// retrievalDepth: 1000,
|
||||
// limit: 50,
|
||||
// sort: [field('location').geoDistance(queryLocation).ascending()],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'goldenWaffle');
|
||||
// });
|
||||
|
||||
it('search full document', async () => {
|
||||
const ppl = firestore
|
||||
.pipeline()
|
||||
.collection(COLLECTION_NAME)
|
||||
.search({
|
||||
query: documentMatches('waffles')
|
||||
// queryEnhancement: 'disabled'
|
||||
});
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expectResults(snapshot, 'goldenWaffle');
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('search a specific field', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches('waffles'),
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'goldenWaffle');
|
||||
// });
|
||||
|
||||
it('geo near query', async () => {
|
||||
const ppl = firestore
|
||||
.pipeline()
|
||||
.collection(COLLECTION_NAME)
|
||||
.search({
|
||||
query: field('location')
|
||||
.geoDistance(new GeoPoint(39.6985, -105.024))
|
||||
.lessThanOrEqual(1000 /* m */)
|
||||
// queryEnhancement: 'disabled'
|
||||
});
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expectResults(snapshot, 'solTacos');
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('conjunction of text search predicates', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: and(
|
||||
// field('menu').matches('waffles'),
|
||||
// field('description').matches('diner')
|
||||
// ),
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'goldenWaffle', 'sunnySideUp');
|
||||
// });
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('conjunction of text search and geo near', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: and(
|
||||
// field('menu').matches('tacos'),
|
||||
// field('location')
|
||||
// .geoDistance(new GeoPoint(39.6985, -105.024))
|
||||
// .lessThan(10_000 /* meters */)
|
||||
// ),
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'solTacos');
|
||||
// });
|
||||
|
||||
it('negate match', async () => {
|
||||
const ppl = firestore
|
||||
.pipeline()
|
||||
.collection(COLLECTION_NAME)
|
||||
.search({
|
||||
query: documentMatches('coffee -waffles')
|
||||
// queryEnhancement: 'disabled'
|
||||
});
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expectResults(snapshot, 'sunnySideUp');
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('rquery search the document with conjunction and disjunction', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: documentMatches('(waffles OR pancakes) AND coffee'),
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'goldenWaffle', 'sunnySideUp');
|
||||
// });
|
||||
|
||||
it('rquery as query param', async () => {
|
||||
const ppl = firestore.pipeline().collection(COLLECTION_NAME).search({
|
||||
query: 'chicken wings'
|
||||
// queryEnhancement: 'disabled'
|
||||
});
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expectResults(snapshot, 'eastsideChicken');
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('rquery supports field paths', async () => {
|
||||
// const ppl = firestore.pipeline().collection(COLLECTION_NAME).search({
|
||||
// query:
|
||||
// 'menu:(waffles OR pancakes) AND description:"breakfast all day"',
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'sunnySideUp');
|
||||
// });
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('conjunction of rquery and expression', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: and(
|
||||
// documentMatches('tacos'),
|
||||
// field('average_price_per_person').between(8, 15)
|
||||
// ),
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'solTacos');
|
||||
// });
|
||||
});
|
||||
|
||||
describe('addFields', () => {
|
||||
it('supports score', async () => {
|
||||
const ppl = firestore
|
||||
.pipeline()
|
||||
.collection(COLLECTION_NAME)
|
||||
.search({
|
||||
query: documentMatches('waffles'),
|
||||
addFields: [score().as('searchScore')]
|
||||
// queryEnhancement: 'disabled'
|
||||
})
|
||||
.select('name', 'searchScore');
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expect(snapshot.results.length).to.equal(1);
|
||||
expect(snapshot.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
expect(snapshot.results[0].get('searchScore')).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('supports multiple fields', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: documentMatches('waffles'),
|
||||
// addFields: [
|
||||
// score().as('searchScore'),
|
||||
// field('menu').snippet('waffles').as('snippet')
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// })
|
||||
// .select('name', 'searchScore', 'snippet');
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expect(snapshot.results.length).to.equal(1);
|
||||
// expect(snapshot.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
// expect(snapshot.results[0].get('searchScore')).to.be.greaterThan(0);
|
||||
// expect(snapshot.results[0].get('snippet')?.length).to.be.greaterThan(
|
||||
// 0
|
||||
// );
|
||||
// });
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// describe('select', () => {
|
||||
// it('topicality score and snippet', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches('waffles'),
|
||||
// select: [
|
||||
// field('name'),
|
||||
// 'location',
|
||||
// score().as('searchScore'),
|
||||
// field('menu').snippet('waffles').as('snippet')
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expect(snapshot.results.length).to.equal(1);
|
||||
// expect(snapshot.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
// expect(snapshot.results[0].get('location')).to.equal(
|
||||
// new GeoPoint(39.7183, -104.9621)
|
||||
// );
|
||||
// expect(snapshot.results[0].get('searchScore')).to.be.greaterThan(0);
|
||||
// expect(snapshot.results[0].get('snippet')?.length).to.be.greaterThan(
|
||||
// 0
|
||||
// );
|
||||
// expect(Object.keys(snapshot.results[0].data()).sort()).to.deep.equal([
|
||||
// 'location',
|
||||
// 'name',
|
||||
// 'searchScore',
|
||||
// 'snippet'
|
||||
// ]);
|
||||
// });
|
||||
// });
|
||||
|
||||
describe('sort', () => {
|
||||
it('by score', async () => {
|
||||
const ppl = firestore
|
||||
.pipeline()
|
||||
.collection(COLLECTION_NAME)
|
||||
.search({
|
||||
query: documentMatches('tacos'),
|
||||
sort: score().descending()
|
||||
// queryEnhancement: 'disabled'
|
||||
});
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expectResults(snapshot, 'eastsideTacos', 'solTacos');
|
||||
});
|
||||
|
||||
it('by distance', async () => {
|
||||
const queryLocation = new GeoPoint(39.6985, -105.024);
|
||||
const ppl = firestore
|
||||
.pipeline()
|
||||
.collection(COLLECTION_NAME)
|
||||
.search({
|
||||
query: field('location')
|
||||
.geoDistance(queryLocation)
|
||||
.lessThanOrEqual(5600),
|
||||
sort: field('location').geoDistance(queryLocation).ascending()
|
||||
// queryEnhancement: 'disabled'
|
||||
});
|
||||
|
||||
const snapshot = await execute(ppl);
|
||||
expectResults(
|
||||
snapshot,
|
||||
'solTacos',
|
||||
'lotusBlossomThai',
|
||||
'mileHighCatch'
|
||||
);
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('by multiple orderings', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches('tacos OR chicken'),
|
||||
// sort: [
|
||||
// field('location')
|
||||
// .geoDistance(new GeoPoint(39.6985, -105.024))
|
||||
// .ascending(),
|
||||
// score().descending()
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(
|
||||
// snapshot,
|
||||
// 'solTacos',
|
||||
// 'eastsideTacos',
|
||||
// 'eastsideChicken'
|
||||
// );
|
||||
// });
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// describe('limit', () => {
|
||||
// it('limits the number of documents returned', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: constant(true),
|
||||
// sort: field('location')
|
||||
// .geoDistance(new GeoPoint(39.6985, -105.024))
|
||||
// .ascending(),
|
||||
// limit: 5,
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(
|
||||
// snapshot,
|
||||
// 'solTacos',
|
||||
// 'lotusBlossomThai',
|
||||
// 'goldenWaffle'
|
||||
// );
|
||||
// });
|
||||
//
|
||||
// it('limits the number of documents scored', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches(
|
||||
// 'chicken OR tacos OR fish OR waffles'
|
||||
// ),
|
||||
// retrievalDepth: 6,
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(
|
||||
// snapshot,
|
||||
// 'eastsideChicken',
|
||||
// 'eastsideTacos',
|
||||
// 'solTacos',
|
||||
// 'mileHighCatch'
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// describe('offset', () => {
|
||||
// it('skips N documents', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: constant(true),
|
||||
// limit: 2,
|
||||
// offset: 2,
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'eastsideChicken', 'eastsideTacos');
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// describe('REQUIRE query expansion', () => {
|
||||
// it('search full document', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: documentMatches('waffles'),
|
||||
// queryEnhancement: 'required'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'goldenWaffle', 'sunnySideUp');
|
||||
// });
|
||||
//
|
||||
// it('search a specific field', async () => {
|
||||
// const ppl = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches('waffles'),
|
||||
// queryEnhancement: 'required'
|
||||
// });
|
||||
//
|
||||
// const snapshot = await execute(ppl);
|
||||
// expectResults(snapshot, 'goldenWaffle', 'sunnySideUp');
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// describe('snippet', () => {
|
||||
// it('snippet options', async () => {
|
||||
// const ppl1 = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches('waffles'),
|
||||
// addFields: [
|
||||
// field('menu')
|
||||
// .snippet({
|
||||
// rquery: 'waffles',
|
||||
// maxSnippetWidth: 10
|
||||
// })
|
||||
// .as('snippet')
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot1 = await execute(ppl1);
|
||||
// expect(snapshot1.results.length).to.equal(1);
|
||||
// expect(snapshot1.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
// expect(snapshot1.results[0].get('snippet')?.length).to.be.greaterThan(0);
|
||||
//
|
||||
// const ppl2 = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: field('menu').matches('waffles'),
|
||||
// addFields: [
|
||||
// field('menu')
|
||||
// .snippet({
|
||||
// rquery: 'waffles',
|
||||
// maxSnippetWidth: 1000
|
||||
// })
|
||||
// .as('snippet')
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot2 = await execute(ppl2);
|
||||
// expect(snapshot2.results.length).to.equal(1);
|
||||
// expect(snapshot2.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
// expect(snapshot2.results[0].get('snippet')?.length).to.be.greaterThan(0);
|
||||
//
|
||||
// expect(snapshot2.results[0].get('snippet')?.length).to.be.greaterThan(
|
||||
// snapshot2.results[0].get('snippet')?.length
|
||||
// );
|
||||
// });
|
||||
//
|
||||
// it('snippet on multiple fields', async () => {
|
||||
// // Get snippet from 1 field
|
||||
// const ppl1 = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: documentMatches('waffle'),
|
||||
// addFields: [
|
||||
// field('menu')
|
||||
// .snippet({
|
||||
// rquery: 'waffles',
|
||||
// maxSnippetWidth: 2000
|
||||
// })
|
||||
// .as('snippet')
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot1 = await execute(ppl1);
|
||||
// expect(snapshot1.results.length).to.equal(1);
|
||||
// expect(snapshot1.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
// expect(snapshot1.results[0].get('snippet')?.length).to.be.greaterThan(0);
|
||||
//
|
||||
// // Get snippet from 2 fields
|
||||
// const ppl2 = firestore
|
||||
// .pipeline()
|
||||
// .collection(COLLECTION_NAME)
|
||||
// .search({
|
||||
// query: documentMatches('waffle'),
|
||||
// addFields: [
|
||||
// concat(field('menu'), field('description'))
|
||||
// .snippet({
|
||||
// rquery: 'waffles',
|
||||
// maxSnippetWidth: 2000
|
||||
// })
|
||||
// .as('snippet')
|
||||
// ],
|
||||
// queryEnhancement: 'disabled'
|
||||
// });
|
||||
//
|
||||
// const snapshot2 = await execute(ppl2);
|
||||
// expect(snapshot2.results.length).to.equal(1);
|
||||
// expect(snapshot2.results[0].get('name')).to.equal('The Golden Waffle');
|
||||
// expect(snapshot2.results[0].get('snippet')?.length).to.be.greaterThan(0);
|
||||
//
|
||||
// // Expect snippet from 2 fields to be longer than snippet from one field
|
||||
// expect(snapshot2.results[0].get('snippet')?.length).to.be.greaterThan(
|
||||
// snapshot2.results[0].get('snippet')?.length
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { ParseContext } from '../../../src/api/parse_context';
|
||||
import { UserDataSource } from '../../../src/lite-api/user_data_reader';
|
||||
import { constant, FunctionExpression } from '../../lite/pipeline_export';
|
||||
import { testUserDataReader } from '../../util/helpers';
|
||||
|
||||
describe('expressions', () => {
|
||||
describe('serialization', () => {
|
||||
let context: ParseContext | undefined;
|
||||
beforeEach(async () => {
|
||||
context = testUserDataReader(false).createContext(
|
||||
UserDataSource.Argument,
|
||||
'beforeEach'
|
||||
);
|
||||
});
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('serializes snippet expression without options', async () => {
|
||||
// const snippetExpression = field('foo').snippet('bar');
|
||||
// snippetExpression._readUserData(context!);
|
||||
//
|
||||
// const proto = snippetExpression._toProto(context!.serializer);
|
||||
//
|
||||
// expect(proto).to.deep.equal({
|
||||
// functionValue: {
|
||||
// name: 'snippet',
|
||||
// args: [
|
||||
// {
|
||||
// 'fieldReferenceValue': 'foo'
|
||||
// },
|
||||
// {
|
||||
// stringValue: 'bar'
|
||||
// }
|
||||
// ],
|
||||
// options: {}
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
// TODO(search) enable with backend support
|
||||
// it('serializes snippet expression with options', async () => {
|
||||
// const snippetExpression = field('foo').snippet({
|
||||
// rquery: 'bar',
|
||||
// maxSnippetWidth: 123,
|
||||
// maxSnippets: 321,
|
||||
// separator: '...'
|
||||
// });
|
||||
// snippetExpression._readUserData(context!);
|
||||
//
|
||||
// const proto = snippetExpression._toProto(context!.serializer);
|
||||
//
|
||||
// expect(proto).to.deep.equal({
|
||||
// functionValue: {
|
||||
// name: 'snippet',
|
||||
// args: [
|
||||
// {
|
||||
// 'fieldReferenceValue': 'foo'
|
||||
// },
|
||||
// {
|
||||
// stringValue: 'bar'
|
||||
// }
|
||||
// ],
|
||||
// options: {
|
||||
// 'max_snippet_width': {
|
||||
// integerValue: '123'
|
||||
// },
|
||||
// 'max_snippets': {
|
||||
// integerValue: '321'
|
||||
// },
|
||||
// separator: {
|
||||
// stringValue: '...'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
it('serializes generic FunctionExpression without options', async () => {
|
||||
const snippetExpression = new FunctionExpression('name', [constant(1)]);
|
||||
snippetExpression._readUserData(context!);
|
||||
|
||||
const proto = snippetExpression._toProto(context!.serializer);
|
||||
|
||||
expect(proto).to.deep.equal({
|
||||
functionValue: {
|
||||
name: 'name',
|
||||
args: [
|
||||
{
|
||||
integerValue: '1'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -29,7 +29,9 @@ import {
|
||||
ExecutePipelineRequest as ProtoExecutePipelineRequest,
|
||||
ExecutePipelineResponse as ProtoExecutePipelineResponse
|
||||
} from '../../../src/protos/firestore_proto_api';
|
||||
import { constant, field } from '../../lite/pipeline_export';
|
||||
import { newTestFirestore } from '../../util/api_helpers';
|
||||
import { describe } from '../../util/mocha_extensions';
|
||||
|
||||
const FIRST_CALL = 0;
|
||||
const EXECUTE_PIPELINE_REQUEST = 3;
|
||||
@@ -200,3 +202,109 @@ describe('execute(Pipeline|PipelineOptions)', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stage serialization', () => {
|
||||
describe('search stage', () => {
|
||||
it('serializes the pipeline', async () => {
|
||||
const firestore = newTestFirestore();
|
||||
const spy = fakePipelineResponse(firestore);
|
||||
|
||||
await execute({
|
||||
pipeline: firestore
|
||||
.pipeline()
|
||||
.collection('foo')
|
||||
.search({
|
||||
query: 'foo',
|
||||
// limit: 1,
|
||||
// retrievalDepth: 2,
|
||||
// offset: 3,
|
||||
// queryEnhancement: 'required',
|
||||
// languageCode: 'en-US',
|
||||
sort: [field('foo').ascending()],
|
||||
addFields: [constant(true).as('bar')]
|
||||
// select: [field('id')]
|
||||
})
|
||||
});
|
||||
|
||||
const executePipelineRequest: ProtoExecutePipelineRequest = {
|
||||
database: 'projects/new-project/databases/(default)',
|
||||
structuredPipeline: {
|
||||
'options': {},
|
||||
'pipeline': {
|
||||
'stages': [
|
||||
{
|
||||
'args': [
|
||||
{
|
||||
'referenceValue': '/foo'
|
||||
}
|
||||
],
|
||||
'name': 'collection',
|
||||
'options': {}
|
||||
},
|
||||
{
|
||||
'args': [],
|
||||
'name': 'search',
|
||||
'options': {
|
||||
'query': {
|
||||
'functionValue': {
|
||||
'args': [
|
||||
{
|
||||
'stringValue': 'foo'
|
||||
}
|
||||
],
|
||||
'name': 'document_matches'
|
||||
}
|
||||
},
|
||||
// 'limit': { integerValue: '1' },
|
||||
// 'retrieval_depth': { integerValue: '2' },
|
||||
// 'offset': { integerValue: '3' },
|
||||
// 'query_enhancement': { stringValue: 'required' },
|
||||
// 'language_code': { stringValue: 'en-US' },
|
||||
// 'select': {
|
||||
// 'mapValue': {
|
||||
// 'fields': {
|
||||
// 'id': {
|
||||
// 'fieldReferenceValue': 'id'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
'sort': {
|
||||
'arrayValue': {
|
||||
'values': [
|
||||
{
|
||||
'mapValue': {
|
||||
'fields': {
|
||||
'direction': {
|
||||
'stringValue': 'ascending'
|
||||
},
|
||||
'expression': {
|
||||
'fieldReferenceValue': 'foo'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
'add_fields': {
|
||||
'mapValue': {
|
||||
'fields': {
|
||||
'bar': {
|
||||
'booleanValue': true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(spy.args[FIRST_CALL][EXECUTE_PIPELINE_REQUEST]).to.deep.equal(
|
||||
executePipelineRequest
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import {
|
||||
USE_EMULATOR,
|
||||
RUN_ENTERPRISE_TESTS
|
||||
getRunEnterpriseTests
|
||||
} from '../integration/util/settings';
|
||||
|
||||
// Helper to make a type itselt (T) and optionally union that with (T['skip'])
|
||||
@@ -44,6 +44,10 @@ declare module 'mocha' {
|
||||
|
||||
// Define helpers
|
||||
export function mixinSkipImplementations(obj: unknown): void {
|
||||
if (Object.getOwnPropertyDescriptor(obj, 'skipEmulator')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, 'skipEmulator', {
|
||||
get(): unknown {
|
||||
if (this === it.skip) {
|
||||
@@ -67,7 +71,7 @@ export function mixinSkipImplementations(obj: unknown): void {
|
||||
if (this === describe.skip) {
|
||||
return this;
|
||||
}
|
||||
if (RUN_ENTERPRISE_TESTS) {
|
||||
if (getRunEnterpriseTests()) {
|
||||
return this.skip;
|
||||
}
|
||||
return this;
|
||||
@@ -82,7 +86,7 @@ export function mixinSkipImplementations(obj: unknown): void {
|
||||
if (this === describe.skip) {
|
||||
return this;
|
||||
}
|
||||
if (!RUN_ENTERPRISE_TESTS) {
|
||||
if (!getRunEnterpriseTests()) {
|
||||
return this.skip;
|
||||
}
|
||||
return this;
|
||||
|
||||
Reference in New Issue
Block a user