@@ -42,7 +42,7 @@ import {
4242} from './pipeline-util' ;
4343import { DocumentReference } from '../reference/document-reference' ;
4444import { PipelineResponse } from '../reference/types' ;
45- import { HasUserData , hasUserData , Serializer } from '../serializer' ;
45+ import { Serializer } from '../serializer' ;
4646import { ApiMapValue } from '../types' ;
4747import * as protos from '../../protos/firestore_v1_proto_api' ;
4848import api = protos . google . firestore . v1 ;
@@ -349,7 +349,7 @@ export class PipelineSource implements firestore.Pipelines.PipelineSource {
349349 */
350350export class Pipeline implements firestore . Pipelines . Pipeline {
351351 constructor (
352- private db : Firestore ,
352+ private db : Firestore | undefined ,
353353 private stages : Stage [ ] ,
354354 ) { }
355355
@@ -433,8 +433,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
433433 : fieldOrOptions . fields ;
434434 const normalizedFields : Map < string , Expression > = selectablesToMap ( fields ) ;
435435
436- this . _validateUserData ( 'select' , normalizedFields ) ;
437-
438436 const internalOptions = {
439437 ...options ,
440438 fields : normalizedFields ,
@@ -503,7 +501,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
503501 const convertedFields : Array < Field > = fields . map ( f =>
504502 isString ( f ) ? field ( f ) : ( f as Field ) ,
505503 ) ;
506- this . _validateUserData ( 'removeFields' , convertedFields ) ;
507504
508505 const innerOptions = {
509506 ...options ,
@@ -602,8 +599,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
602599 const normalizedSelections : Map < string , Expression > =
603600 selectablesToMap ( selections ) ;
604601
605- this . _validateUserData ( 'select' , normalizedSelections ) ;
606-
607602 const internalOptions = {
608603 ...options ,
609604 selections : normalizedSelections ,
@@ -689,7 +684,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
689684 : conditionOrOptions . condition ;
690685 const convertedCondition : BooleanExpression =
691686 condition as BooleanExpression ;
692- this . _validateUserData ( 'where' , convertedCondition ) ;
693687
694688 const internalOptions : InternalWhereStageOptions = {
695689 ...options ,
@@ -906,7 +900,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
906900 ? [ groupOrOptions , ...additionalGroups ]
907901 : groupOrOptions . groups ;
908902 const convertedGroups : Map < string , Expression > = selectablesToMap ( groups ) ;
909- this . _validateUserData ( 'distinct' , convertedGroups ) ;
910903
911904 const internalOptions : InternalDistinctStageOptions = {
912905 ...options ,
@@ -996,7 +989,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
996989 const groups : Array < firestore . Pipelines . Selectable | string > =
997990 isAliasedAggregate ( targetOrOptions ) ? [ ] : ( targetOrOptions . groups ?? [ ] ) ;
998991 const convertedGroups : Map < string , Expression > = selectablesToMap ( groups ) ;
999- this . _validateUserData ( 'aggregate' , convertedGroups ) ;
1000992
1001993 const internalOptions : InternalAggregateStageOptions = {
1002994 ...options ,
@@ -1040,10 +1032,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
10401032 ? toField ( options . distanceField )
10411033 : undefined ;
10421034
1043- this . _validateUserData ( 'findNearest' , field ) ;
1044-
1045- this . _validateUserData ( 'findNearest' , vectorValue ) ;
1046-
10471035 const internalOptions : InternalFindNearestStageOptions = {
10481036 ...options ,
10491037 field,
@@ -1177,7 +1165,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
11771165 ? valueOrOptions
11781166 : valueOrOptions . map ;
11791167 const mapExpr = fieldOrExpression ( fieldNameOrExpr ) ;
1180- this . _validateUserData ( 'replaceWith' , mapExpr ) ;
11811168
11821169 const internalOptions : InternalReplaceWithStageOptions = {
11831170 ...options ,
@@ -1490,7 +1477,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
14901477 ? [ orderingOrOptions , ...additionalOrderings ]
14911478 : orderingOrOptions . orderings ;
14921479 const normalizedOrderings = orderings as Array < Ordering > ;
1493- this . _validateUserData ( 'sort' , normalizedOrderings ) ;
14941480
14951481 const internalOptions : InternalSortStageOptions = {
14961482 ...options ,
@@ -1545,11 +1531,6 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
15451531 }
15461532 } ) ;
15471533
1548- expressionParams . forEach ( param => {
1549- if ( hasUserData ( param ) ) {
1550- param . _validateUserData ( ! ! this . db . _settings . ignoreUndefinedProperties ) ;
1551- }
1552- } ) ;
15531534 return this . _addStage ( new RawStage ( name , expressionParams , options ?? { } ) ) ;
15541535 }
15551536
@@ -1602,7 +1583,19 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
16021583 transactionOrReadTime ?: Uint8Array | Timestamp | api . ITransactionOptions ,
16031584 pipelineExecuteOptions ?: firestore . Pipelines . PipelineExecuteOptions ,
16041585 ) : Promise < PipelineResponse > {
1586+ if ( ! this . db ) {
1587+ throw new Error (
1588+ 'This pipeline was created without a database (e.g., as a subcollection pipeline) and cannot be executed directly. It can only be used as part of another pipeline.' ,
1589+ ) ;
1590+ }
1591+
1592+ // Validates user data in the entire pipeline
1593+ this . _validateUserData (
1594+ this . db . _settings . ignoreUndefinedProperties ?? false ,
1595+ ) ;
1596+
16051597 const util = new ExecutionUtil ( this . db , this . db . _serializer ! ) ;
1598+
16061599 const structuredPipeline = this . _toStructuredPipeline (
16071600 pipelineExecuteOptions ,
16081601 ) ;
@@ -1641,42 +1634,37 @@ export class Pipeline implements firestore.Pipelines.Pipeline {
16411634 * ```
16421635 */
16431636 stream ( ) : NodeJS . ReadableStream {
1637+ if ( ! this . db ) {
1638+ throw new Error (
1639+ 'This pipeline was created without a database (e.g., as a subcollection pipeline) and cannot be executed directly. It can only be used as part of another pipeline.' ,
1640+ ) ;
1641+ }
16441642 const util = new ExecutionUtil ( this . db , this . db . _serializer ! ) ;
16451643 // TODO(pipelines) support options
16461644 const structuredPipeline = this . _toStructuredPipeline ( ) ;
16471645 return util . stream ( structuredPipeline , undefined ) ;
16481646 }
16491647
16501648 _toProto ( ) : api . IPipeline {
1651- const stages : IStage [ ] = this . stages . map ( stage =>
1652- stage . _toProto ( this . db . _serializer ! ) ,
1649+ if ( ! this . db ) {
1650+ throw new Error (
1651+ 'This pipeline was created without a database (e.g., as a subcollection pipeline) and cannot be executed directly. It can only be used as part of another pipeline.' ,
1652+ ) ;
1653+ }
1654+
1655+ const stages : IStage [ ] = this . stages . map (
1656+ // We use a non-null assertion here because we've already checked that
1657+ // 'db' is not null at the start of this function, but TS does not
1658+ // recognize that 'db' can no longer be undefined.
1659+ stage => stage . _toProto ( this . db ! . _serializer ! ) ,
16531660 ) ;
16541661 return { stages} ;
16551662 }
16561663
1657- /**
1658- * @beta
1659- * Validates user data for each expression in the expressionMap.
1660- * @param name Name of the calling function. Used for error messages when invalid user data is encountered.
1661- * @param val
1662- * @returns the expressionMap argument.
1663- * @private
1664- */
1665- _validateUserData <
1666- T extends Map < string , HasUserData > | HasUserData [ ] | HasUserData ,
1667- > ( _ : string , val : T ) : T {
1668- const ignoreUndefinedProperties =
1669- ! ! this . db . _settings . ignoreUndefinedProperties ;
1670- if ( hasUserData ( val ) ) {
1671- val . _validateUserData ( ignoreUndefinedProperties ) ;
1672- } else if ( Array . isArray ( val ) ) {
1673- val . forEach ( readableData => {
1674- readableData . _validateUserData ( ignoreUndefinedProperties ) ;
1675- } ) ;
1676- } else {
1677- val . forEach ( expr => expr . _validateUserData ( ignoreUndefinedProperties ) ) ;
1678- }
1679- return val ;
1664+ _validateUserData ( ignoreUndefinedProperties : boolean ) : void {
1665+ this . stages . forEach ( stage => {
1666+ stage . _validateUserData ( ignoreUndefinedProperties ) ;
1667+ } ) ;
16801668 }
16811669}
16821670
0 commit comments