Skip to main content

firestore/db/
query_models.rs

1// Allow derive_partial_eq_without_eq because some of these types wrap generated gRPC types
2// that might not implement Eq, or their Eq implementation might change.
3#![allow(clippy::derive_partial_eq_without_eq)]
4
5use crate::errors::{
6    FirestoreError, FirestoreInvalidParametersError, FirestoreInvalidParametersPublicDetails,
7};
8use crate::{FirestoreValue, FirestoreVector};
9use gcloud_sdk::google::firestore::v1::*;
10use rsb_derive::Builder;
11
12/// Specifies the target collection(s) for a Firestore query.
13#[derive(Debug, Eq, PartialEq, Clone)]
14pub enum FirestoreQueryCollection {
15    /// Queries a single collection identified by its ID.
16    Single(String),
17    /// Performs a collection group query across all collections with the specified ID(s).
18    /// While Firestore gRPC supports multiple collection IDs here, typically a collection group query
19    /// targets all collections with *one* specific ID.
20    Group(Vec<String>),
21}
22
23#[allow(clippy::to_string_trait_impl)]
24impl ToString for FirestoreQueryCollection {
25    fn to_string(&self) -> String {
26        match self {
27            FirestoreQueryCollection::Single(single) => single.to_string(),
28            FirestoreQueryCollection::Group(group) => group.join(","),
29        }
30    }
31}
32
33impl From<&str> for FirestoreQueryCollection {
34    fn from(collection_id_str: &str) -> Self {
35        FirestoreQueryCollection::Single(collection_id_str.to_string())
36    }
37}
38
39/// Parameters for constructing and executing a Firestore query.
40///
41/// This struct encapsulates all configurable aspects of a query, such as the
42/// target collection, filters, ordering, limits, offsets, cursors, and projections.
43/// It is used by the fluent API and direct query methods to define the query to be sent to Firestore.
44#[derive(Debug, PartialEq, Clone, Builder)]
45pub struct FirestoreQueryParams {
46    /// The parent resource path. For top-level collections, this is typically
47    /// the database path (e.g., "projects/my-project/databases/(default)/documents").
48    /// For sub-collections, it's the path to the parent document.
49    /// If `None`, the query is assumed to be on a top-level collection relative to the
50    /// `FirestoreDb`'s document path.
51    pub parent: Option<String>,
52
53    /// The ID of the collection or collection group to query.
54    pub collection_id: FirestoreQueryCollection,
55
56    /// The maximum number of results to return.
57    pub limit: Option<u32>,
58
59    /// The number of results to skip.
60    pub offset: Option<u32>,
61
62    /// A list of fields and directions to order the results by.
63    pub order_by: Option<Vec<FirestoreQueryOrder>>,
64
65    /// The filter to apply to the query.
66    pub filter: Option<FirestoreQueryFilter>,
67
68    /// If `true`, the query will search all collections located anywhere in the
69    /// database under the `parent` path (if specified) that have the given
70    /// `collection_id`. This is used for collection group queries.
71    /// Defaults to `false` if not set, meaning only direct children collections are queried.
72    pub all_descendants: Option<bool>,
73
74    /// If set, only these fields will be returned in the query results (projection).
75    /// If `None`, all fields are returned.
76    pub return_only_fields: Option<Vec<String>>,
77
78    /// A cursor to define the starting point of the query.
79    pub start_at: Option<FirestoreQueryCursor>,
80
81    /// A cursor to define the ending point of the query.
82    pub end_at: Option<FirestoreQueryCursor>,
83
84    /// Options for requesting an explanation of the query execution plan.
85    pub explain_options: Option<FirestoreExplainOptions>,
86
87    /// Options for performing a vector similarity search (find nearest neighbors).
88    pub find_nearest: Option<FirestoreFindNearestOptions>,
89}
90
91impl TryFrom<FirestoreQueryParams> for StructuredQuery {
92    type Error = FirestoreError;
93
94    fn try_from(params: FirestoreQueryParams) -> Result<Self, Self::Error> {
95        let query_filter = params.filter.map(|f| f.into());
96
97        Ok(StructuredQuery {
98            select: params.return_only_fields.map(|select_only_fields| {
99                structured_query::Projection {
100                    fields: select_only_fields
101                        .into_iter()
102                        .map(|field_name| structured_query::FieldReference {
103                            field_path: field_name,
104                        })
105                        .collect(),
106                }
107            }),
108            start_at: params.start_at.map(|start_at| start_at.into()),
109            end_at: params.end_at.map(|end_at| end_at.into()),
110            limit: params.limit.map(|x| x as i32),
111            offset: params.offset.map(|x| x as i32).unwrap_or(0),
112            order_by: params
113                .order_by
114                .map(|po| po.into_iter().map(|fo| fo.into()).collect())
115                .unwrap_or_default(),
116            from: match params.collection_id {
117                FirestoreQueryCollection::Single(collection_id) => {
118                    vec![structured_query::CollectionSelector {
119                        collection_id,
120                        all_descendants: params.all_descendants.unwrap_or(false),
121                    }]
122                }
123                FirestoreQueryCollection::Group(collection_ids) => collection_ids
124                    .into_iter()
125                    .map(|collection_id| structured_query::CollectionSelector {
126                        collection_id,
127                        all_descendants: params.all_descendants.unwrap_or(false),
128                    })
129                    .collect(),
130            },
131            find_nearest: params
132                .find_nearest
133                .map(|find_nearest| find_nearest.try_into())
134                .transpose()?,
135            r#where: query_filter,
136        })
137    }
138}
139
140/// Represents a filter condition for a Firestore query.
141///
142/// Filters are used to narrow down the documents returned by a query based on
143/// conditions applied to their fields.
144#[derive(Debug, PartialEq, Clone)]
145pub enum FirestoreQueryFilter {
146    /// A composite filter that combines multiple sub-filters using an operator (AND/OR).
147    Composite(FirestoreQueryFilterComposite),
148    /// A unary filter that applies an operation to a single field (e.g., IS NULL, IS NAN).
149    Unary(FirestoreQueryFilterUnary),
150    /// A field filter that compares a field to a value (e.g., equality, greater than).
151    /// The `Option` allows for representing an effectively empty or no-op filter,
152    /// which can be useful in dynamic filter construction.
153    Compare(Option<FirestoreQueryFilterCompare>),
154}
155
156impl From<FirestoreQueryFilter> for structured_query::Filter {
157    fn from(filter: FirestoreQueryFilter) -> Self {
158        let filter_type = match filter {
159            FirestoreQueryFilter::Compare(comp) => comp.map(|cmp| {
160                structured_query::filter::FilterType::FieldFilter(match cmp {
161                    FirestoreQueryFilterCompare::Equal(field_name, fvalue) => {
162                        structured_query::FieldFilter {
163                            field: Some(structured_query::FieldReference {
164                                field_path: field_name,
165                            }),
166                            op: structured_query::field_filter::Operator::Equal.into(),
167                            value: Some(fvalue.value),
168                        }
169                    }
170                    FirestoreQueryFilterCompare::NotEqual(field_name, fvalue) => {
171                        structured_query::FieldFilter {
172                            field: Some(structured_query::FieldReference {
173                                field_path: field_name,
174                            }),
175                            op: structured_query::field_filter::Operator::NotEqual.into(),
176                            value: Some(fvalue.value),
177                        }
178                    }
179                    FirestoreQueryFilterCompare::In(field_name, fvalue) => {
180                        structured_query::FieldFilter {
181                            field: Some(structured_query::FieldReference {
182                                field_path: field_name,
183                            }),
184                            op: structured_query::field_filter::Operator::In.into(),
185                            value: Some(fvalue.value),
186                        }
187                    }
188                    FirestoreQueryFilterCompare::NotIn(field_name, fvalue) => {
189                        structured_query::FieldFilter {
190                            field: Some(structured_query::FieldReference {
191                                field_path: field_name,
192                            }),
193                            op: structured_query::field_filter::Operator::NotIn.into(),
194                            value: Some(fvalue.value),
195                        }
196                    }
197                    FirestoreQueryFilterCompare::ArrayContains(field_name, fvalue) => {
198                        structured_query::FieldFilter {
199                            field: Some(structured_query::FieldReference {
200                                field_path: field_name,
201                            }),
202                            op: structured_query::field_filter::Operator::ArrayContains.into(),
203                            value: Some(fvalue.value),
204                        }
205                    }
206                    FirestoreQueryFilterCompare::ArrayContainsAny(field_name, fvalue) => {
207                        structured_query::FieldFilter {
208                            field: Some(structured_query::FieldReference {
209                                field_path: field_name,
210                            }),
211                            op: structured_query::field_filter::Operator::ArrayContainsAny.into(),
212                            value: Some(fvalue.value),
213                        }
214                    }
215                    FirestoreQueryFilterCompare::LessThan(field_name, fvalue) => {
216                        structured_query::FieldFilter {
217                            field: Some(structured_query::FieldReference {
218                                field_path: field_name,
219                            }),
220                            op: structured_query::field_filter::Operator::LessThan.into(),
221                            value: Some(fvalue.value),
222                        }
223                    }
224                    FirestoreQueryFilterCompare::LessThanOrEqual(field_name, fvalue) => {
225                        structured_query::FieldFilter {
226                            field: Some(structured_query::FieldReference {
227                                field_path: field_name,
228                            }),
229                            op: structured_query::field_filter::Operator::LessThanOrEqual.into(),
230                            value: Some(fvalue.value),
231                        }
232                    }
233                    FirestoreQueryFilterCompare::GreaterThan(field_name, fvalue) => {
234                        structured_query::FieldFilter {
235                            field: Some(structured_query::FieldReference {
236                                field_path: field_name,
237                            }),
238                            op: structured_query::field_filter::Operator::GreaterThan.into(),
239                            value: Some(fvalue.value),
240                        }
241                    }
242                    FirestoreQueryFilterCompare::GreaterThanOrEqual(field_name, fvalue) => {
243                        structured_query::FieldFilter {
244                            field: Some(structured_query::FieldReference {
245                                field_path: field_name,
246                            }),
247                            op: structured_query::field_filter::Operator::GreaterThanOrEqual.into(),
248                            value: Some(fvalue.value),
249                        }
250                    }
251                })
252            }),
253            FirestoreQueryFilter::Composite(composite) => {
254                Some(structured_query::filter::FilterType::CompositeFilter(
255                    structured_query::CompositeFilter {
256                        op: (Into::<structured_query::composite_filter::Operator>::into(
257                            composite.operator,
258                        ))
259                        .into(),
260                        filters: composite
261                            .for_all_filters
262                            .into_iter()
263                            .map(structured_query::Filter::from)
264                            .filter(|filter| filter.filter_type.is_some())
265                            .collect(),
266                    },
267                ))
268            }
269            FirestoreQueryFilter::Unary(unary) => match unary {
270                FirestoreQueryFilterUnary::IsNan(field_name) => {
271                    Some(structured_query::filter::FilterType::UnaryFilter(
272                        structured_query::UnaryFilter {
273                            op: structured_query::unary_filter::Operator::IsNan.into(),
274                            operand_type: Some(structured_query::unary_filter::OperandType::Field(
275                                structured_query::FieldReference {
276                                    field_path: field_name,
277                                },
278                            )),
279                        },
280                    ))
281                }
282                FirestoreQueryFilterUnary::IsNull(field_name) => {
283                    Some(structured_query::filter::FilterType::UnaryFilter(
284                        structured_query::UnaryFilter {
285                            op: structured_query::unary_filter::Operator::IsNull.into(),
286                            operand_type: Some(structured_query::unary_filter::OperandType::Field(
287                                structured_query::FieldReference {
288                                    field_path: field_name,
289                                },
290                            )),
291                        },
292                    ))
293                }
294                FirestoreQueryFilterUnary::IsNotNan(field_name) => {
295                    Some(structured_query::filter::FilterType::UnaryFilter(
296                        structured_query::UnaryFilter {
297                            op: structured_query::unary_filter::Operator::IsNotNan.into(),
298                            operand_type: Some(structured_query::unary_filter::OperandType::Field(
299                                structured_query::FieldReference {
300                                    field_path: field_name,
301                                },
302                            )),
303                        },
304                    ))
305                }
306                FirestoreQueryFilterUnary::IsNotNull(field_name) => {
307                    Some(structured_query::filter::FilterType::UnaryFilter(
308                        structured_query::UnaryFilter {
309                            op: structured_query::unary_filter::Operator::IsNotNull.into(),
310                            operand_type: Some(structured_query::unary_filter::OperandType::Field(
311                                structured_query::FieldReference {
312                                    field_path: field_name,
313                                },
314                            )),
315                        },
316                    ))
317                }
318            },
319        };
320
321        structured_query::Filter { filter_type }
322    }
323}
324
325/// Specifies an ordering for query results based on a field.
326#[derive(Debug, Eq, PartialEq, Clone, Builder)]
327pub struct FirestoreQueryOrder {
328    /// The path to the field to order by (e.g., "name", "address.city").
329    pub field_name: String,
330    /// The direction of the ordering (ascending or descending).
331    pub direction: FirestoreQueryDirection,
332}
333
334impl FirestoreQueryOrder {
335    /// Returns a string representation of the order, e.g., "fieldName asc".
336    pub fn to_string_format(&self) -> String {
337        format!("{} {}", self.field_name, self.direction.to_string())
338    }
339}
340
341impl<S> From<(S, FirestoreQueryDirection)> for FirestoreQueryOrder
342where
343    S: AsRef<str>,
344{
345    fn from(field_order: (S, FirestoreQueryDirection)) -> Self {
346        FirestoreQueryOrder::new(field_order.0.as_ref().to_string(), field_order.1)
347    }
348}
349
350impl From<FirestoreQueryOrder> for structured_query::Order {
351    fn from(order: FirestoreQueryOrder) -> Self {
352        structured_query::Order {
353            field: Some(structured_query::FieldReference {
354                field_path: order.field_name,
355            }),
356            direction: (match order.direction {
357                FirestoreQueryDirection::Ascending => structured_query::Direction::Ascending.into(),
358                FirestoreQueryDirection::Descending => {
359                    structured_query::Direction::Descending.into()
360                }
361            }),
362        }
363    }
364}
365
366/// The direction for ordering query results.
367#[derive(Debug, Eq, PartialEq, Clone)]
368pub enum FirestoreQueryDirection {
369    /// Sort results in ascending order.
370    Ascending,
371    /// Sort results in descending order.
372    Descending,
373}
374
375#[allow(clippy::to_string_trait_impl)]
376impl ToString for FirestoreQueryDirection {
377    fn to_string(&self) -> String {
378        match self {
379            FirestoreQueryDirection::Ascending => "asc".to_string(),
380            FirestoreQueryDirection::Descending => "desc".to_string(),
381        }
382    }
383}
384
385/// A composite filter that combines multiple [`FirestoreQueryFilter`]s.
386#[derive(Debug, PartialEq, Clone, Builder)]
387pub struct FirestoreQueryFilterComposite {
388    /// The list of sub-filters to combine.
389    pub for_all_filters: Vec<FirestoreQueryFilter>,
390    /// The operator used to combine the sub-filters (AND/OR).
391    pub operator: FirestoreQueryFilterCompositeOperator,
392}
393
394/// The operator for combining filters in a [`FirestoreQueryFilterComposite`].
395#[derive(Debug, Eq, PartialEq, Clone)]
396pub enum FirestoreQueryFilterCompositeOperator {
397    /// Logical AND: all sub-filters must be true.
398    And,
399    /// Logical OR: at least one sub-filter must be true.
400    Or,
401}
402
403impl From<FirestoreQueryFilterCompositeOperator> for structured_query::composite_filter::Operator {
404    fn from(operator: FirestoreQueryFilterCompositeOperator) -> Self {
405        match operator {
406            FirestoreQueryFilterCompositeOperator::And => {
407                structured_query::composite_filter::Operator::And
408            }
409            FirestoreQueryFilterCompositeOperator::Or => {
410                structured_query::composite_filter::Operator::Or
411            }
412        }
413    }
414}
415
416/// A unary filter that applies an operation to a single field.
417#[derive(Debug, Eq, PartialEq, Clone)]
418pub enum FirestoreQueryFilterUnary {
419    /// Checks if a field's value is NaN (Not a Number).
420    /// The string argument is the field path.
421    IsNan(String),
422    /// Checks if a field's value is NULL.
423    /// The string argument is the field path.
424    IsNull(String),
425    /// Checks if a field's value is not NaN.
426    /// The string argument is the field path.
427    IsNotNan(String),
428    /// Checks if a field's value is not NULL.
429    /// The string argument is the field path.
430    IsNotNull(String),
431}
432
433/// A field filter that compares a field to a value using a specific operator.
434/// The first `String` argument in each variant is the field path.
435/// The `FirestoreValue` is the value to compare against.
436#[derive(Debug, PartialEq, Clone)]
437pub enum FirestoreQueryFilterCompare {
438    /// Field is less than the value.
439    LessThan(String, FirestoreValue),
440    /// Field is less than or equal to the value.
441    LessThanOrEqual(String, FirestoreValue),
442    /// Field is greater than the value.
443    GreaterThan(String, FirestoreValue),
444    /// Field is greater than or equal to the value.
445    GreaterThanOrEqual(String, FirestoreValue),
446    /// Field is equal to the value.
447    Equal(String, FirestoreValue),
448    /// Field is not equal to the value.
449    NotEqual(String, FirestoreValue),
450    /// Field (which must be an array) contains the value.
451    ArrayContains(String, FirestoreValue),
452    /// Field's value is IN the given array value. The `FirestoreValue` should be an array.
453    In(String, FirestoreValue),
454    /// Field (which must be an array) contains any of the values in the given array value.
455    /// The `FirestoreValue` should be an array.
456    ArrayContainsAny(String, FirestoreValue),
457    /// Field's value is NOT IN the given array value. The `FirestoreValue` should be an array.
458    NotIn(String, FirestoreValue),
459}
460
461/// Represents a cursor for paginating query results.
462///
463/// Cursors define a starting or ending point for a query based on the values
464/// of the fields being ordered by.
465#[derive(Debug, PartialEq, Clone)]
466pub enum FirestoreQueryCursor {
467    /// Starts the query results before the document that has these field values.
468    /// The `Vec<FirestoreValue>` corresponds to the values of the ordered fields.
469    BeforeValue(Vec<FirestoreValue>),
470    /// Starts the query results after the document that has these field values.
471    /// The `Vec<FirestoreValue>` corresponds to the values of the ordered fields.
472    AfterValue(Vec<FirestoreValue>),
473}
474
475impl From<FirestoreQueryCursor> for gcloud_sdk::google::firestore::v1::Cursor {
476    fn from(cursor: FirestoreQueryCursor) -> Self {
477        match cursor {
478            FirestoreQueryCursor::BeforeValue(values) => {
479                gcloud_sdk::google::firestore::v1::Cursor {
480                    values: values.into_iter().map(|value| value.value).collect(),
481                    before: true,
482                }
483            }
484            FirestoreQueryCursor::AfterValue(values) => gcloud_sdk::google::firestore::v1::Cursor {
485                values: values.into_iter().map(|value| value.value).collect(),
486                before: false,
487            },
488        }
489    }
490}
491
492impl From<gcloud_sdk::google::firestore::v1::Cursor> for FirestoreQueryCursor {
493    fn from(cursor: gcloud_sdk::google::firestore::v1::Cursor) -> Self {
494        let firestore_values = cursor
495            .values
496            .into_iter()
497            .map(FirestoreValue::from)
498            .collect();
499        if cursor.before {
500            FirestoreQueryCursor::BeforeValue(firestore_values)
501        } else {
502            FirestoreQueryCursor::AfterValue(firestore_values)
503        }
504    }
505}
506
507/// Parameters for a partitioned query.
508///
509/// Partitioned queries allow you to divide a large query into smaller, parallelizable chunks.
510/// This is useful for exporting data or performing large-scale data processing.
511#[derive(Debug, PartialEq, Clone, Builder)]
512pub struct FirestorePartitionQueryParams {
513    /// The base query parameters to partition.
514    pub query_params: FirestoreQueryParams,
515    /// The desired number of partitions to return. Must be a positive integer.
516    pub partition_count: u32,
517    /// The maximum number of partitions to return in this call, used for paging.
518    /// Must be a positive integer.
519    pub page_size: u32,
520    /// A page token from a previous `PartitionQuery` response to retrieve the next set of partitions.
521    pub page_token: Option<String>,
522}
523
524/// Represents a single partition of a query.
525///
526/// Each partition defines a range of the original query using `start_at` and `end_at` cursors.
527/// Executing a query with these cursors will yield the documents for that specific partition.
528#[derive(Debug, PartialEq, Clone, Builder)]
529pub struct FirestorePartition {
530    /// The cursor indicating the start of this partition.
531    pub start_at: Option<FirestoreQueryCursor>,
532    /// The cursor indicating the end of this partition.
533    pub end_at: Option<FirestoreQueryCursor>,
534}
535
536/// Options for requesting query execution analysis from Firestore.
537///
538/// When `analyze` is true, Firestore will return detailed information about
539/// how the query was executed, including index usage and performance metrics.
540#[derive(Debug, PartialEq, Clone, Builder)]
541pub struct FirestoreExplainOptions {
542    /// If `true`, Firestore will analyze the query and return execution details.
543    /// Defaults to `false` if not specified.
544    pub analyze: Option<bool>,
545}
546
547impl TryFrom<&FirestoreExplainOptions> for gcloud_sdk::google::firestore::v1::ExplainOptions {
548    type Error = FirestoreError;
549    fn try_from(explain_options: &FirestoreExplainOptions) -> Result<Self, Self::Error> {
550        Ok(ExplainOptions {
551            analyze: explain_options.analyze.unwrap_or(false),
552        })
553    }
554}
555
556/// Options for performing a vector similarity search (find nearest neighbors).
557///
558/// This is used to find documents whose vector field is closest to a given query vector.
559#[derive(Debug, PartialEq, Clone, Builder)]
560pub struct FirestoreFindNearestOptions {
561    /// The path to the vector field in your documents to search against.
562    pub field_name: String,
563    /// The query vector to find nearest neighbors for.
564    pub query_vector: FirestoreVector,
565    /// The distance measure to use for comparing vectors.
566    pub distance_measure: FirestoreFindNearestDistanceMeasure,
567    /// The maximum number of nearest neighbors to return.
568    pub neighbors_limit: u32,
569    /// An optional field name to store the calculated distance in the query results.
570    /// If provided, each returned document will include this field with the distance value.
571    pub distance_result_field: Option<String>,
572    /// An optional threshold for the distance. Only neighbors within this distance
573    /// will be returned.
574    pub distance_threshold: Option<f64>,
575}
576
577impl TryFrom<FirestoreFindNearestOptions>
578    for gcloud_sdk::google::firestore::v1::structured_query::FindNearest
579{
580    type Error = FirestoreError;
581
582    fn try_from(options: FirestoreFindNearestOptions) -> Result<Self, Self::Error> {
583        Ok(structured_query::FindNearest {
584            vector_field: Some(structured_query::FieldReference {
585                field_path: options.field_name,
586            }),
587            query_vector: Some(Into::<FirestoreValue>::into(options.query_vector).value),
588            distance_measure: {
589                let distance_measure: structured_query::find_nearest::DistanceMeasure =
590                    options.distance_measure.try_into()?;
591                distance_measure.into()
592            },
593            limit: Some(options.neighbors_limit.try_into().map_err(|e| {
594                FirestoreError::InvalidParametersError(FirestoreInvalidParametersError::new(
595                    FirestoreInvalidParametersPublicDetails::new(
596                        "neighbors_limit".to_string(),
597                        format!(
598                            "Invalid value for neighbors_limit: {}. Maximum allowed value is {}. Error: {}",
599                            options.neighbors_limit,
600                            i32::MAX,
601                            e
602                        ),
603                    ),
604                ))
605            })?),
606            distance_result_field: options.distance_result_field.unwrap_or_default(),
607            distance_threshold: options.distance_threshold,
608        })
609    }
610}
611
612/// Specifies the distance measure for vector similarity searches.
613#[derive(Debug, PartialEq, Clone)]
614pub enum FirestoreFindNearestDistanceMeasure {
615    /// Euclidean distance.
616    Euclidean,
617    /// Cosine similarity (measures the cosine of the angle between two vectors).
618    Cosine,
619    /// Dot product distance.
620    DotProduct,
621}
622
623impl TryFrom<FirestoreFindNearestDistanceMeasure>
624    for structured_query::find_nearest::DistanceMeasure
625{
626    type Error = FirestoreError;
627
628    fn try_from(measure: FirestoreFindNearestDistanceMeasure) -> Result<Self, Self::Error> {
629        match measure {
630            FirestoreFindNearestDistanceMeasure::Euclidean => {
631                Ok(structured_query::find_nearest::DistanceMeasure::Euclidean)
632            }
633            FirestoreFindNearestDistanceMeasure::Cosine => {
634                Ok(structured_query::find_nearest::DistanceMeasure::Cosine)
635            }
636            FirestoreFindNearestDistanceMeasure::DotProduct => {
637                Ok(structured_query::find_nearest::DistanceMeasure::DotProduct)
638            }
639        }
640    }
641}