@@ -64,14 +64,26 @@ import {
6464 Where
6565} from '../lite-api/stage' ;
6666import { Pipeline } from '../lite-api/pipeline' ;
67- import { canonifyQuery , Query , queryEquals , stringifyQuery } from './query' ;
67+ import {
68+ canonifyQuery ,
69+ isCollectionGroupQuery ,
70+ isDocumentQuery ,
71+ LimitType ,
72+ Query ,
73+ queryEquals ,
74+ queryNormalizedOrderBy ,
75+ stringifyQuery
76+ } from './query' ;
6877import {
6978 canonifyTarget ,
7079 Target ,
7180 targetEquals ,
7281 targetIsPipelineTarget
7382} from './target' ;
7483import { ResourcePath } from '../model/path' ;
84+ import { Firestore } from '../api/database' ;
85+ import { doc } from '../lite-api/reference' ;
86+ import { Direction } from './order_by' ;
7587
7688/* eslint @typescript-eslint/no-explicit-any: 0 */
7789
@@ -222,34 +234,37 @@ export function toPipelineFilterCondition(
222234 const value = f . value ;
223235 switch ( f . op ) {
224236 case Operator . LESS_THAN :
225- return and ( field . exists ( ) , field . lt ( value ) ) ;
237+ return and ( field . exists ( ) , field . lt ( Constant . _fromProto ( value ) ) ) ;
226238 case Operator . LESS_THAN_OR_EQUAL :
227- return and ( field . exists ( ) , field . lte ( value ) ) ;
239+ return and ( field . exists ( ) , field . lte ( Constant . _fromProto ( value ) ) ) ;
228240 case Operator . GREATER_THAN :
229- return and ( field . exists ( ) , field . gt ( value ) ) ;
241+ return and ( field . exists ( ) , field . gt ( Constant . _fromProto ( value ) ) ) ;
230242 case Operator . GREATER_THAN_OR_EQUAL :
231- return and ( field . exists ( ) , field . gte ( value ) ) ;
243+ return and ( field . exists ( ) , field . gte ( Constant . _fromProto ( value ) ) ) ;
232244 case Operator . EQUAL :
233- return and ( field . exists ( ) , field . eq ( value ) ) ;
245+ return and ( field . exists ( ) , field . eq ( Constant . _fromProto ( value ) ) ) ;
234246 case Operator . NOT_EQUAL :
235- return and ( field . exists ( ) , field . neq ( value ) ) ;
247+ return and ( field . exists ( ) , field . neq ( Constant . _fromProto ( value ) ) ) ;
236248 case Operator . ARRAY_CONTAINS :
237- return and ( field . exists ( ) , field . arrayContains ( value ) ) ;
249+ return and (
250+ field . exists ( ) ,
251+ field . arrayContains ( Constant . _fromProto ( value ) )
252+ ) ;
238253 case Operator . IN : {
239254 const values = value ?. arrayValue ?. values ?. map ( ( val : any ) =>
240- Constant . of ( val )
255+ Constant . _fromProto ( val )
241256 ) ;
242257 return and ( field . exists ( ) , field . in ( ...values ! ) ) ;
243258 }
244259 case Operator . ARRAY_CONTAINS_ANY : {
245260 const values = value ?. arrayValue ?. values ?. map ( ( val : any ) =>
246- Constant . of ( val )
261+ Constant . _fromProto ( val )
247262 ) ;
248- return and ( field . exists ( ) , field . arrayContainsAny ( values ! ) ) ;
263+ return and ( field . exists ( ) , field . arrayContainsAny ( ... values ! ) ) ;
249264 }
250265 case Operator . NOT_IN : {
251266 const values = value ?. arrayValue ?. values ?. map ( ( val : any ) =>
252- Constant . of ( val )
267+ Constant . _fromProto ( val )
253268 ) ;
254269 return and ( field . exists ( ) , not ( field . in ( ...values ! ) ) ) ;
255270 }
@@ -279,6 +294,56 @@ export function toPipelineFilterCondition(
279294 throw new Error ( `Failed to convert filter to pipeline conditions: ${ f } ` ) ;
280295}
281296
297+ export function toPipeline ( query : Query , db : Firestore ) : Pipeline {
298+ let pipeline : Pipeline ;
299+ if ( isCollectionGroupQuery ( query ) ) {
300+ pipeline = db . pipeline ( ) . collectionGroup ( query . collectionGroup ! ) ;
301+ } else if ( isDocumentQuery ( query ) ) {
302+ pipeline = db . pipeline ( ) . documents ( [ doc ( db , query . path . canonicalString ( ) ) ] ) ;
303+ } else {
304+ pipeline = db . pipeline ( ) . collection ( query . path . canonicalString ( ) ) ;
305+ }
306+
307+ // filters
308+ for ( const filter of query . filters ) {
309+ pipeline = pipeline . where ( toPipelineFilterCondition ( filter ) ) ;
310+ }
311+
312+ // orders
313+ const orders = queryNormalizedOrderBy ( query ) ;
314+ const existsConditions = orders . map ( order =>
315+ Field . of ( order . field . canonicalString ( ) ) . exists ( )
316+ ) ;
317+ if ( existsConditions . length > 1 ) {
318+ pipeline = pipeline . where (
319+ and ( existsConditions [ 0 ] , ...existsConditions . slice ( 1 ) )
320+ ) ;
321+ } else {
322+ pipeline = pipeline . where ( existsConditions [ 0 ] ) ;
323+ }
324+
325+ pipeline = pipeline . sort (
326+ ...orders . map ( order =>
327+ order . dir === Direction . ASCENDING
328+ ? Field . of ( order . field . canonicalString ( ) ) . ascending ( )
329+ : Field . of ( order . field . canonicalString ( ) ) . descending ( )
330+ )
331+ ) ;
332+
333+ // cursors and limits
334+ if ( query . startAt !== null || query . endAt !== null ) {
335+ throw new Error ( 'Cursors are not supported yet.' ) ;
336+ }
337+ if ( query . limitType === LimitType . Last ) {
338+ throw new Error ( 'Limit to last are not supported yet.' ) ;
339+ }
340+ if ( query . limit !== null ) {
341+ pipeline = pipeline . limit ( query . limit ) ;
342+ }
343+
344+ return pipeline ;
345+ }
346+
282347function canonifyExpr ( expr : Expr ) : string {
283348 if ( expr instanceof Field ) {
284349 return `fld(${ expr . fieldName ( ) } )` ;
@@ -534,6 +599,6 @@ export function targetOrPipelineEqual(
534599
535600export function pipelineHasRanges ( pipeline : Pipeline ) : boolean {
536601 return pipeline . stages . some (
537- stage => stage . name === Limit . name || stage . name === Offset . name
602+ stage => stage instanceof Limit || stage instanceof Offset
538603 ) ;
539604}
0 commit comments