Skip to main content

drive/query/
mod.rs

1use std::sync::Arc;
2
3#[cfg(any(feature = "server", feature = "verify"))]
4pub use {
5    conditions::{ValueClause, WhereClause, WhereOperator},
6    drive_document_count_query::{DocumentCountMode, DriveDocumentCountQuery, SplitCountEntry},
7    grovedb::{PathQuery, Query, QueryItem, SizedQuery},
8    ordering::OrderClause,
9    single_document_drive_query::SingleDocumentDriveQuery,
10    single_document_drive_query::SingleDocumentDriveQueryContestedStatus,
11    vote_polls_by_end_date_query::VotePollsByEndDateDriveQuery,
12    vote_query::IdentityBasedVoteDriveQuery,
13};
14
15#[cfg(feature = "server")]
16pub use drive_document_count_query::{
17    CountMode, DocumentCountRequest, DocumentCountResponse, RangeCountOptions,
18    MAX_LIMIT_AS_FAILSAFE,
19};
20// Imports available when either "server" or "verify" features are enabled
21#[cfg(any(feature = "server", feature = "verify"))]
22use {
23    crate::{
24        drive::contract::paths::DataContractPaths,
25        error::{drive::DriveError, query::QuerySyntaxError, Error},
26    },
27    dpp::{
28        data_contract::{
29            accessors::v0::DataContractV0Getters,
30            document_type::{accessors::DocumentTypeV0Getters, methods::DocumentTypeV0Methods},
31            document_type::{DocumentTypeRef, Index, IndexProperty},
32            DataContract,
33        },
34        document::{document_methods::DocumentMethodsV0, Document, DocumentV0Getters},
35        platform_value::{btreemap_extensions::BTreeValueRemoveFromMapHelper, Value},
36        version::PlatformVersion,
37        ProtocolError,
38    },
39    indexmap::IndexMap,
40    sqlparser::{
41        ast::{self, OrderByExpr, Select, Statement, TableFactor::Table, Value::Number},
42        dialect::MySqlDialect,
43        parser::Parser,
44    },
45    std::{collections::BTreeMap, ops::BitXor},
46};
47
48#[cfg(all(feature = "server", feature = "verify"))]
49use crate::verify::RootHash;
50
51#[cfg(feature = "server")]
52use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0;
53#[cfg(feature = "server")]
54pub use grovedb::{
55    query_result_type::{QueryResultElements, QueryResultType},
56    Element, Error as GroveError, TransactionArg,
57};
58
59use dpp::document;
60use dpp::prelude::Identifier;
61use dpp::validation::{SimpleValidationResult, ValidationResult};
62#[cfg(feature = "server")]
63use {
64    crate::{drive::Drive, fees::op::LowLevelDriveOperation},
65    dpp::block::block_info::BlockInfo,
66};
67// Crate-local unconditional imports
68use crate::config::DriveConfig;
69// Crate-local unconditional imports
70use crate::util::common::encode::encode_u64;
71#[cfg(feature = "server")]
72use crate::util::grove_operations::QueryType::StatefulQuery;
73
74// Module declarations that are conditional on either "server" or "verify" features
75#[cfg(any(feature = "server", feature = "verify"))]
76pub mod conditions;
77#[cfg(any(feature = "server", feature = "verify"))]
78mod defaults;
79#[cfg(any(feature = "server", feature = "verify"))]
80pub mod ordering;
81#[cfg(any(feature = "server", feature = "verify"))]
82mod single_document_drive_query;
83
84// Module declarations exclusively for "server" feature
85#[cfg(feature = "server")]
86mod test_index;
87
88#[cfg(any(feature = "server", feature = "verify"))]
89/// Vote poll vote state query module
90pub mod vote_poll_vote_state_query;
91#[cfg(any(feature = "server", feature = "verify"))]
92/// Vote Query module
93pub mod vote_query;
94
95#[cfg(any(feature = "server", feature = "verify"))]
96/// Vote poll contestant votes query module
97pub mod vote_poll_contestant_votes_query;
98
99#[cfg(any(feature = "server", feature = "verify"))]
100/// Vote polls by end date query
101pub mod vote_polls_by_end_date_query;
102
103#[cfg(any(feature = "server", feature = "verify"))]
104/// Vote polls by document type query
105pub mod vote_polls_by_document_type_query;
106
107/// Function type for looking up a contract by identifier
108///
109/// This function is used to look up a contract by its identifier.
110/// It should be implemented by the caller in order to provide data
111/// contract required for operations like proof verification.
112#[cfg(any(feature = "server", feature = "verify"))]
113pub type ContractLookupFn<'a> =
114    dyn Fn(&Identifier) -> Result<Option<Arc<DataContract>>, Error> + 'a;
115
116/// Creates a [ContractLookupFn] function that returns provided data contract when requested.
117///
118/// # Arguments
119///
120/// * `data_contract` - [Arc<DataContract>](DataContract) to return
121///
122/// # Returns
123///
124/// [ContractLookupFn] that will return the `data_contract`, or `None` if
125/// the requested contract is not the same as the provided one.
126#[cfg(any(feature = "server", feature = "verify"))]
127pub fn contract_lookup_fn_for_contract<'a>(
128    data_contract: Arc<DataContract>,
129) -> Box<ContractLookupFn<'a>> {
130    let func = move |id: &Identifier| -> Result<Option<Arc<DataContract>>, Error> {
131        if data_contract.id().ne(id) {
132            return Ok(None);
133        }
134        Ok(Some(Arc::clone(&data_contract)))
135    };
136    Box::new(func)
137}
138
139/// A query to get the votes given out by an identity
140#[cfg(any(feature = "server", feature = "verify"))]
141pub mod contested_resource_votes_given_by_identity_query;
142/// A query to get contested documents before they have been awarded
143#[cfg(any(feature = "server", feature = "verify"))]
144pub mod drive_contested_document_query;
145
146/// A query to get the block counts of proposers in an epoch
147#[cfg(any(feature = "server", feature = "verify"))]
148pub mod proposer_block_count_query;
149
150/// A query to get the identity's token balance
151#[cfg(any(feature = "server", feature = "verify"))]
152pub mod identity_token_balance_drive_query;
153/// A query to get the identity's token info
154#[cfg(any(feature = "server", feature = "verify"))]
155pub mod identity_token_info_drive_query;
156
157/// Document subscription filtering
158#[cfg(any(feature = "server", feature = "verify"))]
159pub mod filter;
160/// A query to get the token's status
161#[cfg(any(feature = "server", feature = "verify"))]
162pub mod token_status_drive_query;
163
164/// A query to count documents using CountTree elements
165#[cfg(any(feature = "server", feature = "verify"))]
166pub mod drive_document_count_query;
167
168/// A Query Syntax Validation Result that contains data
169pub type QuerySyntaxValidationResult<TData> = ValidationResult<TData, QuerySyntaxError>;
170
171/// A Query Syntax Validation Result
172pub type QuerySyntaxSimpleValidationResult = SimpleValidationResult<QuerySyntaxError>;
173
174#[cfg(any(feature = "server", feature = "verify"))]
175/// Represents a starting point for a query based on a specific document.
176///
177/// This struct encapsulates all the necessary details to define the starting
178/// conditions for a query, including the document to start from, its type,
179/// associated index property, and whether the document itself should be included
180/// in the query results.
181#[derive(Debug, Clone)]
182pub struct StartAtDocument<'a> {
183    /// The document that serves as the starting point for the query.
184    pub document: Document,
185
186    /// The type of the document, providing metadata about its schema and structure.
187    pub document_type: DocumentTypeRef<'a>,
188
189    /// Indicates whether the starting document itself should be included in the query results.
190    /// - `true`: The document is included in the results.
191    /// - `false`: The document is excluded, and the query starts from the next matching document.
192    pub included: bool,
193}
194
195/// Internal clauses struct
196#[cfg(any(feature = "server", feature = "verify"))]
197#[derive(Clone, Debug, PartialEq, Default)]
198pub struct InternalClauses {
199    /// Primary key in clause
200    pub primary_key_in_clause: Option<WhereClause>,
201    /// Primary key equal clause
202    pub primary_key_equal_clause: Option<WhereClause>,
203    /// In clause
204    pub in_clause: Option<WhereClause>,
205    /// Range clause
206    pub range_clause: Option<WhereClause>,
207    /// Equal clause
208    pub equal_clauses: BTreeMap<String, WhereClause>,
209}
210
211impl InternalClauses {
212    #[cfg(any(feature = "server", feature = "verify"))]
213    /// Returns true if the clause is a valid format.
214    pub fn verify(&self) -> bool {
215        // There can only be 1 primary key clause, or many other clauses
216        if self
217            .primary_key_in_clause
218            .is_some()
219            .bitxor(self.primary_key_equal_clause.is_some())
220        {
221            // One is set, all rest must be empty
222            !(self.in_clause.is_some()
223                || self.range_clause.is_some()
224                || !self.equal_clauses.is_empty())
225        } else {
226            !(self.primary_key_in_clause.is_some() && self.primary_key_equal_clause.is_some())
227        }
228    }
229
230    #[cfg(any(feature = "server", feature = "verify"))]
231    /// Returns true if the query clause is for primary keys.
232    pub fn is_for_primary_key(&self) -> bool {
233        self.primary_key_in_clause.is_some() || self.primary_key_equal_clause.is_some()
234    }
235
236    #[cfg(any(feature = "server", feature = "verify"))]
237    /// Returns true if self is empty.
238    pub fn is_empty(&self) -> bool {
239        self.in_clause.is_none()
240            && self.range_clause.is_none()
241            && self.equal_clauses.is_empty()
242            && self.primary_key_in_clause.is_none()
243            && self.primary_key_equal_clause.is_none()
244    }
245
246    #[cfg(any(feature = "server", feature = "verify"))]
247    /// Extracts the `WhereClause`s and returns them as type `InternalClauses`.
248    pub fn extract_from_clauses(all_where_clauses: Vec<WhereClause>) -> Result<Self, Error> {
249        let primary_key_equal_clauses_array = all_where_clauses
250            .iter()
251            .filter_map(|where_clause| match where_clause.operator {
252                WhereOperator::Equal => match where_clause.is_identifier() {
253                    true => Some(where_clause.clone()),
254                    false => None,
255                },
256                _ => None,
257            })
258            .collect::<Vec<WhereClause>>();
259
260        let primary_key_in_clauses_array = all_where_clauses
261            .iter()
262            .filter_map(|where_clause| match where_clause.operator {
263                WhereOperator::In => match where_clause.is_identifier() {
264                    true => Some(where_clause.clone()),
265                    false => None,
266                },
267                _ => None,
268            })
269            .collect::<Vec<WhereClause>>();
270
271        let (equal_clauses, range_clause, in_clause) =
272            WhereClause::group_clauses(&all_where_clauses)?;
273
274        let primary_key_equal_clause = match primary_key_equal_clauses_array.len() {
275            0 => Ok(None),
276            1 => Ok(Some(
277                primary_key_equal_clauses_array
278                    .first()
279                    .expect("there must be a value")
280                    .clone(),
281            )),
282            _ => Err(Error::Query(
283                QuerySyntaxError::DuplicateNonGroupableClauseSameField(
284                    "There should only be one equal clause for the primary key",
285                ),
286            )),
287        }?;
288
289        let primary_key_in_clause = match primary_key_in_clauses_array.len() {
290            0 => Ok(None),
291            1 => Ok(Some(
292                primary_key_in_clauses_array
293                    .first()
294                    .expect("there must be a value")
295                    .clone(),
296            )),
297            _ => Err(Error::Query(
298                QuerySyntaxError::DuplicateNonGroupableClauseSameField(
299                    "There should only be one in clause for the primary key",
300                ),
301            )),
302        }?;
303
304        let internal_clauses = InternalClauses {
305            primary_key_equal_clause,
306            primary_key_in_clause,
307            in_clause,
308            range_clause,
309            equal_clauses,
310        };
311
312        match internal_clauses.verify() {
313            true => Ok(internal_clauses),
314            false => Err(Error::Query(
315                QuerySyntaxError::InvalidWhereClauseComponents("Query has invalid where clauses"),
316            )),
317        }
318    }
319
320    /// Validate this collection of InternalClauses against the document schema
321    #[cfg(any(feature = "server", feature = "verify"))]
322    pub fn validate_against_schema(
323        &self,
324        document_type: DocumentTypeRef,
325    ) -> QuerySyntaxSimpleValidationResult {
326        // Basic composition
327        if !self.verify() {
328            return QuerySyntaxSimpleValidationResult::new_with_error(
329                QuerySyntaxError::InvalidWhereClauseComponents(
330                    "invalid composition of where clauses",
331                ),
332            );
333        }
334
335        // Validate in_clause against schema
336        if let Some(in_clause) = &self.in_clause {
337            // Forbid $id in non-primary-key clauses
338            if in_clause.field == "$id" {
339                return QuerySyntaxSimpleValidationResult::new_with_error(
340                    QuerySyntaxError::InvalidWhereClauseComponents(
341                        "use primary_key_* clauses for $id",
342                    ),
343                );
344            }
345            let result = in_clause.validate_against_schema(document_type);
346            if !result.is_valid() {
347                return result;
348            }
349        }
350
351        // Validate range_clause against schema
352        if let Some(range_clause) = &self.range_clause {
353            // Forbid $id in non-primary-key clauses
354            if range_clause.field == "$id" {
355                return QuerySyntaxSimpleValidationResult::new_with_error(
356                    QuerySyntaxError::InvalidWhereClauseComponents(
357                        "use primary_key_* clauses for $id",
358                    ),
359                );
360            }
361            let result = range_clause.validate_against_schema(document_type);
362            if !result.is_valid() {
363                return result;
364            }
365        }
366
367        // Validate equal_clauses against schema
368        for (field, eq_clause) in &self.equal_clauses {
369            // Forbid $id in non-primary-key clauses
370            if field.as_str() == "$id" {
371                return QuerySyntaxSimpleValidationResult::new_with_error(
372                    QuerySyntaxError::InvalidWhereClauseComponents(
373                        "use primary_key_* clauses for $id",
374                    ),
375                );
376            }
377            let result = eq_clause.validate_against_schema(document_type);
378            if !result.is_valid() {
379                return result;
380            }
381        }
382
383        // Validate primary key clauses typing
384        if let Some(pk_eq) = &self.primary_key_equal_clause {
385            if pk_eq.operator != WhereOperator::Equal
386                || !matches!(pk_eq.value, Value::Identifier(_))
387            {
388                return QuerySyntaxSimpleValidationResult::new_with_error(
389                    QuerySyntaxError::InvalidWhereClauseComponents(
390                        "primary key equality must compare an identifier",
391                    ),
392                );
393            }
394        }
395        if let Some(pk_in) = &self.primary_key_in_clause {
396            if pk_in.operator != WhereOperator::In {
397                return QuerySyntaxSimpleValidationResult::new_with_error(
398                    QuerySyntaxError::InvalidWhereClauseComponents(
399                        "primary key IN must use IN operator",
400                    ),
401                );
402            }
403            // enforce array shape and no duplicates/size
404            let result = pk_in.in_values();
405            if !result.is_valid() {
406                return QuerySyntaxSimpleValidationResult::new_with_errors(result.errors);
407            }
408            if let Value::Array(arr) = &pk_in.value {
409                if !arr.iter().all(|v| matches!(v, Value::Identifier(_))) {
410                    return QuerySyntaxSimpleValidationResult::new_with_error(
411                        QuerySyntaxError::InvalidWhereClauseComponents(
412                            "primary key IN must contain identifiers",
413                        ),
414                    );
415                }
416            } else {
417                return QuerySyntaxSimpleValidationResult::new_with_error(
418                    QuerySyntaxError::InvalidWhereClauseComponents(
419                        "primary key IN must contain an array of identifiers",
420                    ),
421                );
422            }
423        }
424
425        QuerySyntaxSimpleValidationResult::default()
426    }
427}
428
429impl From<InternalClauses> for Vec<WhereClause> {
430    fn from(clauses: InternalClauses) -> Self {
431        let mut result: Self = clauses.equal_clauses.into_values().collect();
432
433        if let Some(clause) = clauses.in_clause {
434            result.push(clause);
435        };
436        if let Some(clause) = clauses.primary_key_equal_clause {
437            result.push(clause);
438        };
439        if let Some(clause) = clauses.primary_key_in_clause {
440            result.push(clause);
441        };
442        if let Some(clause) = clauses.range_clause {
443            result.push(clause);
444        };
445
446        result
447    }
448}
449
450#[cfg(any(feature = "server", feature = "verify"))]
451/// Drive query struct
452#[derive(Debug, PartialEq, Clone)]
453pub struct DriveDocumentQuery<'a> {
454    ///DataContract
455    pub contract: &'a DataContract,
456    /// Document type
457    pub document_type: DocumentTypeRef<'a>,
458    /// Internal clauses
459    pub internal_clauses: InternalClauses,
460    /// Offset
461    pub offset: Option<u16>,
462    /// Limit
463    pub limit: Option<u16>,
464    /// Order by
465    pub order_by: IndexMap<String, OrderClause>,
466    /// Start at document id
467    pub start_at: Option<[u8; 32]>,
468    /// Start at included
469    pub start_at_included: bool,
470    /// Block time
471    pub block_time_ms: Option<u64>,
472}
473
474impl<'a> DriveDocumentQuery<'a> {
475    /// Gets a document by their primary key
476    #[cfg(any(feature = "server", feature = "verify"))]
477    pub fn new_primary_key_single_item_query(
478        contract: &'a DataContract,
479        document_type: DocumentTypeRef<'a>,
480        id: Identifier,
481    ) -> Self {
482        DriveDocumentQuery {
483            contract,
484            document_type,
485            internal_clauses: InternalClauses {
486                primary_key_in_clause: None,
487                primary_key_equal_clause: Some(WhereClause {
488                    field: document::property_names::ID.to_string(),
489                    operator: WhereOperator::Equal,
490                    value: Value::Identifier(id.to_buffer()),
491                }),
492                in_clause: None,
493                range_clause: None,
494                equal_clauses: Default::default(),
495            },
496            offset: None,
497            limit: None,
498            order_by: Default::default(),
499            start_at: None,
500            start_at_included: false,
501            block_time_ms: None,
502        }
503    }
504
505    #[cfg(feature = "server")]
506    /// Returns any item
507    pub fn any_item_query(contract: &'a DataContract, document_type: DocumentTypeRef<'a>) -> Self {
508        DriveDocumentQuery {
509            contract,
510            document_type,
511            internal_clauses: Default::default(),
512            offset: None,
513            limit: Some(1),
514            order_by: Default::default(),
515            start_at: None,
516            start_at_included: true,
517            block_time_ms: None,
518        }
519    }
520
521    #[cfg(feature = "server")]
522    /// Returns all items
523    pub fn all_items_query(
524        contract: &'a DataContract,
525        document_type: DocumentTypeRef<'a>,
526        limit: Option<u16>,
527    ) -> Self {
528        DriveDocumentQuery {
529            contract,
530            document_type,
531            internal_clauses: Default::default(),
532            offset: None,
533            limit,
534            order_by: Default::default(),
535            start_at: None,
536            start_at_included: true,
537            block_time_ms: None,
538        }
539    }
540
541    #[cfg(any(feature = "server", feature = "verify"))]
542    /// Returns true if the query clause if for primary keys.
543    pub fn is_for_primary_key(&self) -> bool {
544        self.internal_clauses.is_for_primary_key()
545            || (self.internal_clauses.is_empty()
546                && (self.order_by.is_empty()
547                    || (self.order_by.len() == 1
548                        && self
549                            .order_by
550                            .keys()
551                            .collect::<Vec<&String>>()
552                            .first()
553                            .unwrap()
554                            .as_str()
555                            == "$id")))
556    }
557
558    #[cfg(feature = "cbor_query")]
559    /// Converts a query CBOR to a `DriveQuery`.
560    pub fn from_cbor(
561        query_cbor: &[u8],
562        contract: &'a DataContract,
563        document_type: DocumentTypeRef<'a>,
564        config: &DriveConfig,
565    ) -> Result<Self, Error> {
566        let query_document_value: Value = ciborium::de::from_reader(query_cbor).map_err(|_| {
567            Error::Query(QuerySyntaxError::DeserializationError(
568                "unable to decode query from cbor".to_string(),
569            ))
570        })?;
571        Self::from_value(query_document_value, contract, document_type, config)
572    }
573
574    #[cfg(any(feature = "server", feature = "verify"))]
575    /// Converts a query Value to a `DriveQuery`.
576    pub fn from_value(
577        query_value: Value,
578        contract: &'a DataContract,
579        document_type: DocumentTypeRef<'a>,
580        config: &DriveConfig,
581    ) -> Result<Self, Error> {
582        let query_document: BTreeMap<String, Value> = query_value.into_btree_string_map()?;
583        Self::from_btree_map_value(query_document, contract, document_type, config)
584    }
585
586    #[cfg(any(feature = "server", feature = "verify"))]
587    /// Converts a query Value to a `DriveQuery`.
588    pub fn from_btree_map_value(
589        mut query_document: BTreeMap<String, Value>,
590        contract: &'a DataContract,
591        document_type: DocumentTypeRef<'a>,
592        config: &DriveConfig,
593    ) -> Result<Self, Error> {
594        if let Some(contract_id) = query_document
595            .remove_optional_identifier("contract_id")
596            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?
597        {
598            if contract.id() != contract_id {
599                return Err(ProtocolError::IdentifierError(format!(
600                    "data contract id mismatch, expected: {}, got: {}",
601                    contract.id(),
602                    contract_id
603                ))
604                .into());
605            };
606        }
607
608        if let Some(document_type_name) = query_document
609            .remove_optional_string("document_type_name")
610            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?
611        {
612            if document_type.name() != &document_type_name {
613                return Err(ProtocolError::IdentifierError(format!(
614                    "document type name mismatch, expected: {}, got: {}",
615                    document_type.name(),
616                    document_type_name
617                ))
618                .into());
619            }
620        }
621
622        let maybe_limit: Option<u16> = query_document
623            .remove_optional_integer("limit")
624            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
625
626        let limit = maybe_limit
627            .map_or(Some(config.default_query_limit), |limit_value| {
628                if limit_value == 0 || limit_value > config.default_query_limit {
629                    None
630                } else {
631                    Some(limit_value)
632                }
633            })
634            .ok_or(Error::Query(QuerySyntaxError::InvalidLimit(format!(
635                "limit greater than max limit {}",
636                config.max_query_limit
637            ))))?;
638
639        let offset: Option<u16> = query_document
640            .remove_optional_integer("offset")
641            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
642
643        let block_time_ms: Option<u64> = query_document
644            .remove_optional_integer("blockTime")
645            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
646
647        let all_where_clauses: Vec<WhereClause> =
648            query_document
649                .remove("where")
650                .map_or(Ok(vec![]), |id_cbor| {
651                    if let Value::Array(clauses) = id_cbor {
652                        clauses
653                            .iter()
654                            .map(|where_clause| {
655                                if let Value::Array(clauses_components) = where_clause {
656                                    WhereClause::from_components(clauses_components)
657                                } else {
658                                    Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
659                                        "where clause must be an array".to_string(),
660                                    )))
661                                }
662                            })
663                            .collect::<Result<Vec<WhereClause>, Error>>()
664                    } else {
665                        Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
666                            "where clause must be an array".to_string(),
667                        )))
668                    }
669                })?;
670
671        let internal_clauses = InternalClauses::extract_from_clauses(all_where_clauses)?;
672
673        let start_at_option = query_document.remove("startAt");
674        let start_after_option = query_document.remove("startAfter");
675        if start_after_option.is_some() && start_at_option.is_some() {
676            return Err(Error::Query(QuerySyntaxError::DuplicateStartConditions(
677                "only one of startAt or startAfter should be provided",
678            )));
679        }
680
681        let mut start_at_included = true;
682
683        let mut start_option: Option<Value> = None;
684
685        if start_after_option.is_some() {
686            start_option = start_after_option;
687            start_at_included = false;
688        } else if start_at_option.is_some() {
689            start_option = start_at_option;
690            start_at_included = true;
691        }
692
693        let start_at: Option<[u8; 32]> = start_option
694            .map(|v| {
695                v.into_identifier()
696                    .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))
697                    .map(|identifier| identifier.into_buffer())
698            })
699            .transpose()?;
700
701        let order_by: IndexMap<String, OrderClause> =
702            query_document
703                .remove("orderBy")
704                .map_or(Ok(IndexMap::new()), |id_cbor| {
705                    if let Value::Array(clauses) = id_cbor {
706                        clauses
707                            .into_iter()
708                            .filter_map(|order_clause| {
709                                if let Value::Array(clauses_components) = order_clause {
710                                    let order_clause =
711                                        OrderClause::from_components(&clauses_components)
712                                            .map_err(Error::from);
713                                    match order_clause {
714                                        Ok(order_clause) => {
715                                            Some(Ok((order_clause.field.clone(), order_clause)))
716                                        }
717                                        Err(err) => Some(Err(err)),
718                                    }
719                                } else {
720                                    None
721                                }
722                            })
723                            .collect::<Result<IndexMap<String, OrderClause>, Error>>()
724                    } else {
725                        Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
726                            "order clauses must be an array",
727                        )))
728                    }
729                })?;
730
731        if !query_document.is_empty() {
732            return Err(Error::Query(QuerySyntaxError::Unsupported(format!(
733                "unsupported syntax in where clause: {:?}",
734                query_document
735            ))));
736        }
737
738        Ok(DriveDocumentQuery {
739            contract,
740            document_type,
741            internal_clauses,
742            limit: Some(limit),
743            offset,
744            order_by,
745            start_at,
746            start_at_included,
747            block_time_ms,
748        })
749    }
750
751    #[cfg(any(feature = "server", feature = "verify"))]
752    /// Converts a query Value to a `DriveQuery`.
753    #[allow(clippy::too_many_arguments)]
754    pub fn from_decomposed_values(
755        where_clause: Value,
756        order_by: Option<Value>,
757        maybe_limit: Option<u16>,
758        start_at: Option<[u8; 32]>,
759        start_at_included: bool,
760        block_time_ms: Option<u64>,
761        contract: &'a DataContract,
762        document_type: DocumentTypeRef<'a>,
763        config: &DriveConfig,
764    ) -> Result<Self, Error> {
765        let limit = maybe_limit
766            .map_or(Some(config.default_query_limit), |limit_value| {
767                if limit_value == 0 || limit_value > config.default_query_limit {
768                    None
769                } else {
770                    Some(limit_value)
771                }
772            })
773            .ok_or(Error::Query(QuerySyntaxError::InvalidLimit(format!(
774                "limit greater than max limit {}",
775                config.max_query_limit
776            ))))?;
777
778        let all_where_clauses: Vec<WhereClause> = match where_clause {
779            Value::Null => Ok(vec![]),
780            Value::Array(clauses) => clauses
781                .iter()
782                .map(|where_clause| {
783                    if let Value::Array(clauses_components) = where_clause {
784                        WhereClause::from_components(clauses_components)
785                    } else {
786                        Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
787                            "where clause must be an array".to_string(),
788                        )))
789                    }
790                })
791                .collect::<Result<Vec<WhereClause>, Error>>(),
792            _ => Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
793                "where clause must be an array".to_string(),
794            ))),
795        }?;
796
797        let internal_clauses = InternalClauses::extract_from_clauses(all_where_clauses)?;
798
799        let order_by: IndexMap<String, OrderClause> = order_by
800            .map_or(vec![], |id_cbor| {
801                if let Value::Array(clauses) = id_cbor {
802                    clauses
803                        .iter()
804                        .filter_map(|order_clause| {
805                            if let Value::Array(clauses_components) = order_clause {
806                                OrderClause::from_components(clauses_components).ok()
807                            } else {
808                                None
809                            }
810                        })
811                        .collect()
812                } else {
813                    vec![]
814                }
815            })
816            .iter()
817            .map(|order_clause| Ok((order_clause.field.clone(), order_clause.to_owned())))
818            .collect::<Result<IndexMap<String, OrderClause>, Error>>()?;
819
820        Ok(DriveDocumentQuery {
821            contract,
822            document_type,
823            internal_clauses,
824            offset: None,
825            limit: Some(limit),
826            order_by,
827            start_at,
828            start_at_included,
829            block_time_ms,
830        })
831    }
832
833    #[cfg(any(feature = "server", feature = "verify"))]
834    /// Converts a SQL expression to a `DriveQuery`.
835    pub fn from_sql_expr(
836        sql_string: &str,
837        contract: &'a DataContract,
838        config: Option<&DriveConfig>,
839    ) -> Result<Self, Error> {
840        let dialect: MySqlDialect = MySqlDialect {};
841        let statements: Vec<Statement> = Parser::parse_sql(&dialect, sql_string)
842            .map_err(|e| Error::Query(QuerySyntaxError::SQLParsingError(e)))?;
843
844        // Should ideally iterate over each statement
845        let first_statement =
846            statements
847                .first()
848                .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
849                    "Issue parsing sql getting first statement".to_string(),
850                )))?;
851
852        let query: &ast::Query = match first_statement {
853            ast::Statement::Query(query_struct) => Some(query_struct),
854            _ => None,
855        }
856        .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
857            "Issue parsing sql: not a query".to_string(),
858        )))?;
859
860        let max_limit = config
861            .map(|config| config.max_query_limit)
862            .unwrap_or(DriveConfig::default().max_query_limit);
863
864        let limit: u16 = if let Some(limit_expr) = &query.limit {
865            match limit_expr {
866                ast::Expr::Value(Number(num_string, _)) => {
867                    let cast_num_string: &String = num_string;
868                    let user_limit = cast_num_string.parse::<u16>().map_err(|e| {
869                        Error::Query(QuerySyntaxError::InvalidLimit(format!(
870                            "limit could not be parsed {}",
871                            e
872                        )))
873                    })?;
874                    if user_limit > max_limit {
875                        return Err(Error::Query(QuerySyntaxError::InvalidLimit(format!(
876                            "limit {} greater than max limit {}",
877                            user_limit, max_limit
878                        ))));
879                    }
880                    user_limit
881                }
882                result => {
883                    return Err(Error::Query(QuerySyntaxError::InvalidLimit(format!(
884                        "expression not a limit {}",
885                        result
886                    ))));
887                }
888            }
889        } else {
890            config
891                .map(|config| config.default_query_limit)
892                .unwrap_or(DriveConfig::default().default_query_limit)
893        };
894
895        let order_by: IndexMap<String, OrderClause> = query
896            .order_by
897            .iter()
898            .map(|order_exp: &OrderByExpr| {
899                let ascending = order_exp.asc.is_none() || order_exp.asc.unwrap();
900                let field = order_exp.expr.to_string();
901                (field.clone(), OrderClause { field, ascending })
902            })
903            .collect::<IndexMap<String, OrderClause>>();
904
905        // Grab the select section of the query
906        let select: &Select = match &*query.body {
907            ast::SetExpr::Select(select) => Some(select),
908            _ => None,
909        }
910        .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
911            "Issue parsing sql: Not a select".to_string(),
912        )))?;
913
914        // Get the document type from the 'from' section
915        let document_type_name = match &select
916            .from
917            .first()
918            .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
919                "Invalid query: missing from section".to_string(),
920            )))?
921            .relation
922        {
923            Table { name, .. } => name.0.first().as_ref().map(|identifier| &identifier.value),
924            _ => None,
925        }
926        .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
927            "Issue parsing sql: invalid from value".to_string(),
928        )))?;
929
930        let document_type =
931            contract
932                .document_types()
933                .get(document_type_name)
934                .ok_or(Error::Query(QuerySyntaxError::DocumentTypeNotFound(
935                    "document type not found in contract",
936                )))?;
937
938        // Restrictions
939        // only binary where clauses are supported
940        // i.e. [<fieldname>, <operator>, <value>]
941        // [and] is used to separate where clauses
942        // currently where clauses are either binary operations or list descriptions (in clauses)
943        // hence once [and] is encountered [left] and [right] must be only one of the above
944        // i.e other where clauses
945        // e.g. firstname = wisdom and lastname = ogwu
946        // if op is not [and] then [left] or [right] must not be a binary operation or list description
947        let mut all_where_clauses: Vec<WhereClause> = Vec::new();
948        let selection_tree = select.selection.as_ref();
949
950        // Where clauses are optional
951        if let Some(selection_tree) = selection_tree {
952            WhereClause::build_where_clauses_from_operations(
953                selection_tree,
954                document_type,
955                &mut all_where_clauses,
956            )?;
957        }
958
959        let internal_clauses = InternalClauses::extract_from_clauses(all_where_clauses)?;
960
961        let start_at_option = None; //todo
962        let start_after_option = None; //todo
963        let mut start_at_included = true;
964        let mut start_option: Option<Value> = None;
965
966        if start_after_option.is_some() {
967            start_option = start_after_option;
968            start_at_included = false;
969        } else if start_at_option.is_some() {
970            start_option = start_at_option;
971            start_at_included = true;
972        }
973
974        let start_at: Option<[u8; 32]> = start_option
975            .map(|v| {
976                v.into_identifier()
977                    .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))
978                    .map(|identifier| identifier.into_buffer())
979            })
980            .transpose()?;
981
982        Ok(DriveDocumentQuery {
983            contract,
984            document_type: document_type.as_ref(),
985            internal_clauses,
986            offset: None,
987            limit: Some(limit),
988            order_by,
989            start_at,
990            start_at_included,
991            block_time_ms: None,
992        })
993    }
994
995    /// Serialize drive query to CBOR format.
996    ///
997    /// FIXME: The data contract is only referred as ID, and document type as its name.
998    /// This can change in the future to include full data contract and document type.
999    #[cfg(feature = "cbor_query")]
1000    pub fn to_cbor(&self) -> Result<Vec<u8>, Error> {
1001        let data: BTreeMap<String, Value> = self.into();
1002        let cbor: BTreeMap<String, ciborium::Value> = Value::convert_to_cbor_map(data)?;
1003        let mut output = Vec::new();
1004
1005        ciborium::ser::into_writer(&cbor, &mut output)
1006            .map_err(|e| ProtocolError::PlatformSerializationError(e.to_string()))?;
1007        Ok(output)
1008    }
1009
1010    #[cfg(any(feature = "server", feature = "verify"))]
1011    /// Operations to construct a path query.
1012    pub fn start_at_document_path_and_key(&self, starts_at: &[u8; 32]) -> (Vec<Vec<u8>>, Vec<u8>) {
1013        if self.document_type.documents_keep_history() {
1014            let document_holding_path = self.contract.documents_with_history_primary_key_path(
1015                self.document_type.name().as_str(),
1016                starts_at,
1017            );
1018            (
1019                document_holding_path
1020                    .into_iter()
1021                    .map(|key| key.to_vec())
1022                    .collect::<Vec<_>>(),
1023                vec![0],
1024            )
1025        } else {
1026            let document_holding_path = self
1027                .contract
1028                .documents_primary_key_path(self.document_type.name().as_str());
1029            (
1030                document_holding_path
1031                    .into_iter()
1032                    .map(|key| key.to_vec())
1033                    .collect::<Vec<_>>(),
1034                starts_at.to_vec(),
1035            )
1036        }
1037    }
1038
1039    #[cfg(feature = "server")]
1040    /// Operations to construct a path query.
1041    pub fn construct_path_query_operations(
1042        &self,
1043        drive: &Drive,
1044        include_start_at_for_proof: bool,
1045        transaction: TransactionArg,
1046        drive_operations: &mut Vec<LowLevelDriveOperation>,
1047        platform_version: &PlatformVersion,
1048    ) -> Result<PathQuery, Error> {
1049        let drive_version = &platform_version.drive;
1050        // First we should get the overall document_type_path
1051        let document_type_path = self
1052            .contract
1053            .document_type_path(self.document_type.name().as_str())
1054            .into_iter()
1055            .map(|a| a.to_vec())
1056            .collect::<Vec<Vec<u8>>>();
1057
1058        let (starts_at_document, start_at_path_query) = match &self.start_at {
1059            None => Ok((None, None)),
1060            Some(starts_at) => {
1061                // First if we have a startAt or startsAfter we must get the element
1062                // from the backing store
1063
1064                let (start_at_document_path, start_at_document_key) =
1065                    self.start_at_document_path_and_key(starts_at);
1066                let start_at_document = drive
1067                    .grove_get(
1068                        start_at_document_path.as_slice().into(),
1069                        &start_at_document_key,
1070                        StatefulQuery,
1071                        transaction,
1072                        drive_operations,
1073                        drive_version,
1074                    )
1075                    .map_err(|e| match e {
1076                        Error::GroveDB(e)
1077                            if matches!(
1078                                e.as_ref(),
1079                                GroveError::PathKeyNotFound(_)
1080                                    | GroveError::PathNotFound(_)
1081                                    | GroveError::PathParentLayerNotFound(_)
1082                            ) =>
1083                        {
1084                            let error_message = if self.start_at_included {
1085                                "startAt document not found"
1086                            } else {
1087                                "startAfter document not found"
1088                            };
1089
1090                            Error::Query(QuerySyntaxError::StartDocumentNotFound(error_message))
1091                        }
1092                        _ => e,
1093                    })?
1094                    .ok_or(Error::Drive(DriveError::CorruptedCodeExecution(
1095                        "expected a value",
1096                    )))?;
1097
1098                let path_query =
1099                    PathQuery::new_single_key(start_at_document_path, start_at_document_key);
1100
1101                if let Element::Item(item, _) = start_at_document {
1102                    let document = Document::from_bytes(
1103                        item.as_slice(),
1104                        self.document_type,
1105                        platform_version,
1106                    )?;
1107                    Ok((Some((document, self.start_at_included)), Some(path_query)))
1108                } else {
1109                    Err(Error::Drive(DriveError::CorruptedDocumentPath(
1110                        "Holding paths should only have items",
1111                    )))
1112                }
1113            }
1114        }?;
1115        let mut main_path_query = if self.is_for_primary_key() {
1116            self.get_primary_key_path_query(
1117                document_type_path,
1118                starts_at_document,
1119                platform_version,
1120            )
1121        } else {
1122            self.get_non_primary_key_path_query(
1123                document_type_path,
1124                starts_at_document,
1125                platform_version,
1126            )
1127        }?;
1128        if !include_start_at_for_proof {
1129            return Ok(main_path_query);
1130        }
1131
1132        if let Some(start_at_path_query) = start_at_path_query {
1133            let limit = main_path_query.query.limit.take();
1134            let mut merged = PathQuery::merge(
1135                vec![&start_at_path_query, &main_path_query],
1136                &platform_version.drive.grove_version,
1137            )
1138            .map_err(Error::from)?;
1139            merged.query.limit = limit.map(|a| a.saturating_add(1));
1140            Ok(merged)
1141        } else {
1142            Ok(main_path_query)
1143        }
1144    }
1145
1146    #[cfg(any(feature = "server", feature = "verify"))]
1147    /// Operations to construct a path query.
1148    pub fn construct_path_query(
1149        &self,
1150        starts_at_document: Option<Document>,
1151        platform_version: &PlatformVersion,
1152    ) -> Result<PathQuery, Error> {
1153        // First we should get the overall document_type_path
1154        let document_type_path = self
1155            .contract
1156            .document_type_path(self.document_type.name().as_str())
1157            .into_iter()
1158            .map(|a| a.to_vec())
1159            .collect::<Vec<Vec<u8>>>();
1160        let starts_at_document = starts_at_document
1161            .map(|starts_at_document| (starts_at_document, self.start_at_included));
1162        if self.is_for_primary_key() {
1163            self.get_primary_key_path_query(
1164                document_type_path,
1165                starts_at_document,
1166                platform_version,
1167            )
1168        } else {
1169            self.get_non_primary_key_path_query(
1170                document_type_path,
1171                starts_at_document,
1172                platform_version,
1173            )
1174        }
1175    }
1176
1177    #[cfg(any(feature = "server", feature = "verify"))]
1178    /// Returns a path query given a document type path and starting document.
1179    pub fn get_primary_key_path_query(
1180        &self,
1181        document_type_path: Vec<Vec<u8>>,
1182        starts_at_document: Option<(Document, bool)>,
1183        platform_version: &PlatformVersion,
1184    ) -> Result<PathQuery, Error> {
1185        let mut path = document_type_path;
1186
1187        // Add primary key ($id) subtree
1188        path.push(vec![0]);
1189
1190        if let Some(primary_key_equal_clause) = &self.internal_clauses.primary_key_equal_clause {
1191            let mut query = Query::new();
1192            let key = self.document_type.serialize_value_for_key(
1193                "$id",
1194                &primary_key_equal_clause.value,
1195                platform_version,
1196            )?;
1197            query.insert_key(key);
1198
1199            if self.document_type.documents_keep_history() {
1200                // if the documents keep history then we should insert a subquery
1201                if let Some(block_time) = self.block_time_ms {
1202                    let encoded_block_time = encode_u64(block_time);
1203                    let mut sub_query = Query::new_with_direction(false);
1204                    sub_query.insert_range_to_inclusive(..=encoded_block_time);
1205                    query.set_subquery(sub_query);
1206                } else {
1207                    query.set_subquery_key(vec![0]);
1208                }
1209            }
1210
1211            Ok(PathQuery::new(path, SizedQuery::new(query, Some(1), None)))
1212        } else {
1213            // This is for a range
1214            let left_to_right = if self.order_by.keys().len() == 1 {
1215                if self.order_by.keys().next().unwrap() != "$id" {
1216                    return Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1217                        "order by should include $id only",
1218                    )));
1219                }
1220
1221                let order_clause = self.order_by.get("$id").unwrap();
1222
1223                order_clause.ascending
1224            } else {
1225                true
1226            };
1227
1228            let mut query = Query::new_with_direction(left_to_right);
1229            // If there is a start_at_document, we need to get the value that it has for the
1230            // current field.
1231            let starts_at_key_option = match starts_at_document {
1232                None => None,
1233                Some((document, included)) => {
1234                    // if the key doesn't exist then we should ignore the starts at key
1235                    document
1236                        .get_raw_for_document_type(
1237                            "$id",
1238                            self.document_type,
1239                            None,
1240                            platform_version,
1241                        )?
1242                        .map(|raw_value_option| (raw_value_option, included))
1243                }
1244            };
1245
1246            if let Some(primary_key_in_clause) = &self.internal_clauses.primary_key_in_clause {
1247                let in_values = primary_key_in_clause.in_values().into_data_with_error()??;
1248
1249                match starts_at_key_option {
1250                    None => {
1251                        for value in in_values.iter() {
1252                            let key = self.document_type.serialize_value_for_key(
1253                                "$id",
1254                                value,
1255                                platform_version,
1256                            )?;
1257                            query.insert_key(key)
1258                        }
1259                    }
1260                    Some((starts_at_key, included)) => {
1261                        for value in in_values.iter() {
1262                            let key = self.document_type.serialize_value_for_key(
1263                                "$id",
1264                                value,
1265                                platform_version,
1266                            )?;
1267
1268                            if (left_to_right && starts_at_key < key)
1269                                || (!left_to_right && starts_at_key > key)
1270                                || (included && starts_at_key == key)
1271                            {
1272                                query.insert_key(key);
1273                            }
1274                        }
1275                    }
1276                }
1277
1278                if self.document_type.documents_keep_history() {
1279                    // if the documents keep history then we should insert a subquery
1280                    if let Some(_block_time) = self.block_time_ms {
1281                        //todo
1282                        return Err(Error::Query(QuerySyntaxError::Unsupported(
1283                            "Not yet implemented".to_string(),
1284                        )));
1285                        // in order to be able to do this we would need limited subqueries
1286                        // as we only want the first element before the block_time
1287
1288                        // let encoded_block_time = encode_float(block_time)?;
1289                        // let mut sub_query = Query::new_with_direction(false);
1290                        // sub_query.insert_range_to_inclusive(..=encoded_block_time);
1291                        // query.set_subquery(sub_query);
1292                    } else {
1293                        query.set_subquery_key(vec![0]);
1294                    }
1295                }
1296
1297                Ok(PathQuery::new(
1298                    path,
1299                    SizedQuery::new(query, self.limit, self.offset),
1300                ))
1301            } else {
1302                // this is a range on all elements
1303                match starts_at_key_option {
1304                    None => {
1305                        query.insert_all();
1306                    }
1307                    Some((starts_at_key, included)) => match left_to_right {
1308                        true => match included {
1309                            true => query.insert_range_from(starts_at_key..),
1310                            false => query.insert_range_after(starts_at_key..),
1311                        },
1312                        false => match included {
1313                            true => query.insert_range_to_inclusive(..=starts_at_key),
1314                            false => query.insert_range_to(..starts_at_key),
1315                        },
1316                    },
1317                }
1318
1319                if self.document_type.documents_keep_history() {
1320                    // if the documents keep history then we should insert a subquery
1321                    if let Some(_block_time) = self.block_time_ms {
1322                        return Err(Error::Query(QuerySyntaxError::Unsupported(
1323                            "this query is not supported".to_string(),
1324                        )));
1325                        // in order to be able to do this we would need limited subqueries
1326                        // as we only want the first element before the block_time
1327
1328                        // let encoded_block_time = encode_float(block_time)?;
1329                        // let mut sub_query = Query::new_with_direction(false);
1330                        // sub_query.insert_range_to_inclusive(..=encoded_block_time);
1331                        // query.set_subquery(sub_query);
1332                    } else {
1333                        query.set_subquery_key(vec![0]);
1334                    }
1335                }
1336
1337                Ok(PathQuery::new(
1338                    path,
1339                    SizedQuery::new(query, self.limit, self.offset),
1340                ))
1341            }
1342        }
1343    }
1344
1345    #[cfg(any(feature = "server", feature = "verify"))]
1346    /// Finds the best index for the query.
1347    pub fn find_best_index(&self, platform_version: &PlatformVersion) -> Result<&Index, Error> {
1348        let equal_fields = self
1349            .internal_clauses
1350            .equal_clauses
1351            .keys()
1352            .map(|s| s.as_str())
1353            .collect::<Vec<&str>>();
1354        let in_field = self
1355            .internal_clauses
1356            .in_clause
1357            .as_ref()
1358            .map(|in_clause| in_clause.field.as_str());
1359        let range_field = self
1360            .internal_clauses
1361            .range_clause
1362            .as_ref()
1363            .map(|range_clause| range_clause.field.as_str());
1364        let mut fields = equal_fields;
1365        if let Some(range_field) = range_field {
1366            fields.push(range_field);
1367        }
1368        if let Some(in_field) = in_field {
1369            fields.push(in_field);
1370            //if there is an in_field, it always takes precedence
1371        }
1372
1373        let order_by_keys: Vec<&str> = self
1374            .order_by
1375            .keys()
1376            .map(|key: &String| {
1377                let str = key.as_str();
1378                if !fields.contains(&str) {
1379                    fields.push(str);
1380                }
1381                str
1382            })
1383            .collect();
1384
1385        let (index, difference) = self
1386            .document_type
1387            .index_for_types(
1388                fields.as_slice(),
1389                in_field,
1390                order_by_keys.as_slice(),
1391                platform_version,
1392            )?
1393            .ok_or(Error::Query(
1394                QuerySyntaxError::WhereClauseOnNonIndexedProperty(format!(
1395                    "query must be for valid indexes, valid indexes are: {:?}",
1396                    self.document_type.indexes()
1397                )),
1398            ))?;
1399        if difference > defaults::MAX_INDEX_DIFFERENCE {
1400            return Err(Error::Query(QuerySyntaxError::QueryTooFarFromIndex(
1401                "query must better match an existing index",
1402            )));
1403        }
1404        Ok(index)
1405    }
1406
1407    #[cfg(any(feature = "server", feature = "verify"))]
1408    /// Returns a `QueryItem` given a start key and query direction.
1409    pub fn query_item_for_starts_at_key(starts_at_key: Vec<u8>, left_to_right: bool) -> QueryItem {
1410        if left_to_right {
1411            QueryItem::RangeAfter(starts_at_key..)
1412        } else {
1413            QueryItem::RangeTo(..starts_at_key)
1414        }
1415    }
1416
1417    #[cfg(any(feature = "server", feature = "verify"))]
1418    /// Returns a `Query` that either starts at or after the given document ID if given.
1419    fn inner_query_from_starts_at_for_id(
1420        starts_at_document: Option<&StartAtDocument>,
1421        left_to_right: bool,
1422    ) -> Query {
1423        // We only need items after the start at document
1424        let mut inner_query = Query::new_with_direction(left_to_right);
1425
1426        if let Some(StartAtDocument {
1427            document, included, ..
1428        }) = starts_at_document
1429        {
1430            let start_at_key = document.id().to_vec();
1431            if *included {
1432                inner_query.insert_range_from(start_at_key..)
1433            } else {
1434                inner_query.insert_range_after(start_at_key..)
1435            }
1436        } else {
1437            // No starts at document, take all NULL items
1438            inner_query.insert_all();
1439        }
1440        inner_query
1441    }
1442
1443    #[cfg(any(feature = "server", feature = "verify"))]
1444    /// Returns a `Query` that either starts at or after the given key.
1445    fn inner_query_starts_from_key(
1446        start_at_key: Option<Vec<u8>>,
1447        left_to_right: bool,
1448        included: bool,
1449    ) -> Query {
1450        // We only need items after the start at document
1451        let mut inner_query = Query::new_with_direction(left_to_right);
1452
1453        if left_to_right {
1454            if let Some(start_at_key) = start_at_key {
1455                if included {
1456                    inner_query.insert_range_from(start_at_key..);
1457                } else {
1458                    inner_query.insert_range_after(start_at_key..);
1459                }
1460            } else {
1461                inner_query.insert_all();
1462            }
1463        } else if included {
1464            if let Some(start_at_key) = start_at_key {
1465                inner_query.insert_range_to_inclusive(..=start_at_key);
1466            } else {
1467                inner_query.insert_key(vec![]);
1468            }
1469        } else if let Some(start_at_key) = start_at_key {
1470            inner_query.insert_range_to(..start_at_key);
1471        } else {
1472            //todo: really not sure if this is correct
1473            // Should investigate more
1474            inner_query.insert_key(vec![]);
1475        }
1476
1477        inner_query
1478    }
1479
1480    #[cfg(any(feature = "server", feature = "verify"))]
1481    /// Returns a `Query` that either starts at or after the given document if given.
1482    fn inner_query_from_starts_at(
1483        starts_at_document: Option<&StartAtDocument>,
1484        indexed_property: &IndexProperty,
1485        left_to_right: bool,
1486        platform_version: &PlatformVersion,
1487    ) -> Result<Query, Error> {
1488        let mut inner_query = Query::new_with_direction(left_to_right);
1489        if let Some(StartAtDocument {
1490            document,
1491            document_type,
1492            included,
1493        }) = starts_at_document
1494        {
1495            // We only need items after the start at document
1496            let start_at_key = document.get_raw_for_document_type(
1497                indexed_property.name.as_str(),
1498                *document_type,
1499                None,
1500                platform_version,
1501            )?;
1502            // We want to get items starting at the start key
1503            if let Some(start_at_key) = start_at_key {
1504                if left_to_right {
1505                    if *included {
1506                        inner_query.insert_range_from(start_at_key..)
1507                    } else {
1508                        inner_query.insert_range_after(start_at_key..)
1509                    }
1510                } else if *included {
1511                    inner_query.insert_range_to_inclusive(..=start_at_key)
1512                } else {
1513                    inner_query.insert_range_to(..start_at_key)
1514                }
1515            } else if left_to_right {
1516                inner_query.insert_all();
1517            } else {
1518                inner_query.insert_key(vec![]);
1519            }
1520        } else {
1521            // No starts at document, take all NULL items
1522            inner_query.insert_all();
1523        }
1524        Ok(inner_query)
1525    }
1526
1527    #[cfg(any(feature = "server", feature = "verify"))]
1528    fn recursive_create_query(
1529        left_over_index_properties: &[&IndexProperty],
1530        unique: bool,
1531        starts_at_document: Option<&StartAtDocument>, //for key level, included
1532        indexed_property: &IndexProperty,
1533        order_by: Option<&IndexMap<String, OrderClause>>,
1534        platform_version: &PlatformVersion,
1535    ) -> Result<Option<Query>, Error> {
1536        match left_over_index_properties.split_first() {
1537            None => Ok(None),
1538            Some((first, left_over)) => {
1539                let left_to_right = if let Some(order_by) = order_by {
1540                    order_by
1541                        .get(first.name.as_str())
1542                        .map(|order_clause| order_clause.ascending)
1543                        .unwrap_or(first.ascending)
1544                } else {
1545                    first.ascending
1546                };
1547
1548                let mut inner_query = Self::inner_query_from_starts_at(
1549                    starts_at_document,
1550                    indexed_property,
1551                    left_to_right,
1552                    platform_version,
1553                )?;
1554                DriveDocumentQuery::recursive_insert_on_query(
1555                    &mut inner_query,
1556                    left_over,
1557                    unique,
1558                    starts_at_document,
1559                    left_to_right,
1560                    order_by,
1561                    platform_version,
1562                )?;
1563                Ok(Some(inner_query))
1564            }
1565        }
1566    }
1567
1568    #[cfg(any(feature = "server", feature = "verify"))]
1569    /// Recursively queries as long as there are leftover index properties.
1570    /// The in_start_at_document_sub_path_needing_conditional is interesting.
1571    /// It indicates whether the start at document should be applied as a conditional
1572    /// For example if we have a tree
1573    /// Root
1574    /// ├── model
1575    /// │   ├── sedan
1576    /// │   │   ├── brand_name
1577    /// │   │   │   ├── Honda
1578    /// │   │   │   │   ├── car_type
1579    /// │   │   │   │   │   ├── Accord
1580    /// │   │   │   │   │   │   ├── 0
1581    /// │   │   │   │   │   │   │   ├── a47d2...
1582    /// │   │   │   │   │   │   │   ├── e19c8...
1583    /// │   │   │   │   │   │   │   └── f1a7b...
1584    /// │   │   │   │   │   └── Civic
1585    /// │   │   │   │   │       ├── 0
1586    /// │   │   │   │   │       │   ├── b65a7...
1587    /// │   │   │   │   │       │   └── c43de...
1588    /// │   │   │   ├── Toyota
1589    /// │   │   │   │   ├── car_type
1590    /// │   │   │   │   │   ├── Camry
1591    /// │   │   │   │   │   │   ├── 0
1592    /// │   │   │   │   │   │   │   └── 1a9d2...
1593    /// │   │   │   │   │   └── Corolla
1594    /// │   │   │   │   │       ├── 0
1595    /// │   │   │   │   │       │   ├── 3f7b4...
1596    /// │   │   │   │   │       │   ├── 4e8fa...
1597    /// │   │   │   │   │       │   └── 9b1c6...
1598    /// │   ├── suv
1599    /// │   │   ├── brand_name
1600    /// │   │   │   ├── Ford*
1601    /// │   │   │   │   ├── car_type*
1602    /// │   │   │   │   │   ├── Escape*
1603    /// │   │   │   │   │   │   ├── 0
1604    /// │   │   │   │   │   │   │   ├── 102bc...
1605    /// │   │   │   │   │   │   │   ├── 29f8e... <- Set After this document
1606    /// │   │   │   │   │   │   │   └── 6b1a3...
1607    /// │   │   │   │   │   └── Explorer
1608    /// │   │   │   │   │       ├── 0
1609    /// │   │   │   │   │       │   ├── b2a9d...
1610    /// │   │   │   │   │       │   └── f4d5c...
1611    /// │   │   │   ├── Nissan
1612    /// │   │   │   │   ├── car_type
1613    /// │   │   │   │   │   ├── Rogue
1614    /// │   │   │   │   │   │   ├── 0
1615    /// │   │   │   │   │   │   │   ├── 5a9c3...
1616    /// │   │   │   │   │   │   │   └── 7e4b9...
1617    /// │   │   │   │   │   └── Murano
1618    /// │   │   │   │   │       ├── 0
1619    /// │   │   │   │   │       │   ├── 8f6a2...
1620    /// │   │   │   │   │       │   └── 9c7d4...
1621    /// │   ├── truck
1622    /// │   │   ├── brand_name
1623    /// │   │   │   ├── Ford
1624    /// │   │   │   │   ├── car_type
1625    /// │   │   │   │   │   ├── F-150
1626    /// │   │   │   │   │   │   ├── 0
1627    /// │   │   │   │   │   │   │   ├── 72a3b...
1628    /// │   │   │   │   │   │   │   └── 94c8e...
1629    /// │   │   │   │   │   └── Ranger
1630    /// │   │   │   │   │       ├── 0
1631    /// │   │   │   │   │       │   ├── 3f4b1...
1632    /// │   │   │   │   │       │   ├── 6e7d2...
1633    /// │   │   │   │   │       │   └── 8a1f5...
1634    /// │   │   │   ├── Toyota
1635    /// │   │   │   │   ├── car_type
1636    /// │   │   │   │   │   ├── Tundra
1637    /// │   │   │   │   │   │   ├── 0
1638    /// │   │   │   │   │   │   │   ├── 7c9a4...
1639    /// │   │   │   │   │   │   │   └── a5d1e...
1640    /// │   │   │   │   │   └── Tacoma
1641    /// │   │   │   │   │       ├── 0
1642    /// │   │   │   │   │       │   ├── 1e7f4...
1643    /// │   │   │   │   │       │   └── 6b9d3...
1644    ///
1645    /// let's say we are asking for suv's after 29f8e
1646    /// here the * denotes the area needing a conditional
1647    /// We need a conditional subquery on Ford to say only things after Ford (with Ford included)
1648    /// We need a conditional subquery on Escape to say only things after Escape (with Escape included)
1649    fn recursive_insert_on_query(
1650        query: &mut Query,
1651        left_over_index_properties: &[&IndexProperty],
1652        unique: bool,
1653        starts_at_document: Option<&StartAtDocument>, //for key level, included
1654        default_left_to_right: bool,
1655        order_by: Option<&IndexMap<String, OrderClause>>,
1656        platform_version: &PlatformVersion,
1657    ) -> Result<Option<Query>, Error> {
1658        match left_over_index_properties.split_first() {
1659            None => {
1660                match unique {
1661                    true => {
1662                        query.set_subquery_key(vec![0]);
1663
1664                        // In the case things are NULL we allow to have multiple values
1665                        let inner_query = Self::inner_query_from_starts_at_for_id(
1666                            starts_at_document,
1667                            true, //for ids we always go left to right
1668                        );
1669                        query.add_conditional_subquery(
1670                            QueryItem::Key(b"".to_vec()),
1671                            Some(vec![vec![0]]),
1672                            Some(inner_query),
1673                        );
1674                    }
1675                    false => {
1676                        query.set_subquery_key(vec![0]);
1677                        // we just get all by document id order ascending
1678                        let full_query =
1679                            Self::inner_query_from_starts_at_for_id(None, default_left_to_right);
1680                        query.set_subquery(full_query);
1681
1682                        let inner_query = Self::inner_query_from_starts_at_for_id(
1683                            starts_at_document,
1684                            default_left_to_right,
1685                        );
1686
1687                        query.add_conditional_subquery(
1688                            QueryItem::Key(b"".to_vec()),
1689                            Some(vec![vec![0]]),
1690                            Some(inner_query),
1691                        );
1692                    }
1693                }
1694                Ok(None)
1695            }
1696            Some((first, left_over)) => {
1697                let left_to_right = if let Some(order_by) = order_by {
1698                    order_by
1699                        .get(first.name.as_str())
1700                        .map(|order_clause| order_clause.ascending)
1701                        .unwrap_or(first.ascending)
1702                } else {
1703                    first.ascending
1704                };
1705
1706                if let Some(start_at_document_inner) = starts_at_document {
1707                    let StartAtDocument {
1708                        document,
1709                        document_type,
1710                        included,
1711                    } = start_at_document_inner;
1712                    let start_at_key = document
1713                        .get_raw_for_document_type(
1714                            first.name.as_str(),
1715                            *document_type,
1716                            None,
1717                            platform_version,
1718                        )
1719                        .ok()
1720                        .flatten();
1721
1722                    // We should always include if we have left_over
1723                    let non_conditional_included =
1724                        !left_over.is_empty() || *included || start_at_key.is_none();
1725
1726                    let mut non_conditional_query = Self::inner_query_starts_from_key(
1727                        start_at_key.clone(),
1728                        left_to_right,
1729                        non_conditional_included,
1730                    );
1731
1732                    // We place None here on purpose, this has been well-thought-out
1733                    // and should not change. The reason is that the path of the start
1734                    // at document is used only on the conditional subquery and not on the
1735                    // main query
1736                    // for example in the following
1737                    // Our query will be with $ownerId == a3f9b81c4d7e6a9f5b1c3e8a2d9c4f7b
1738                    // With start after 8f2d5
1739                    // We want to get from 2024-11-17T12:45:00Z
1740                    // withdrawal
1741                    // ├── $ownerId
1742                    // │   ├── a3f9b81c4d7e6a9f5b1c3e8a2d9c4f7b
1743                    // │   │   ├── $updatedAt
1744                    // │   │   │   ├── 2024-11-17T12:45:00Z <- conditional subquery here
1745                    // │   │   │   │   ├── status
1746                    // │   │   │   │   │   ├── 0
1747                    // │   │   │   │   │   │   ├── 7a9f1...
1748                    // │   │   │   │   │   │   └── 4b8c3...
1749                    // │   │   │   │   │   ├── 1
1750                    // │   │   │   │   │   │   ├── 8f2d5... <- start after
1751                    // │   │   │   │   │   │   └── 5c1e4...
1752                    // │   │   │   │   │   ├── 2
1753                    // │   │   │   │   │   │   ├── 2e7a9...
1754                    // │   │   │   │   │   │   └── 1c8b3...
1755                    // │   │   │   ├── 2024-11-18T11:25:00Z <- we want all statuses here, so normal subquery, with None as start at document
1756                    // │   │   │   │   ├── status
1757                    // │   │   │   │   │   ├── 0
1758                    // │   │   │   │   │   │   └── 1a4f2...
1759                    // │   │   │   │   │   ├── 2
1760                    // │   │   │   │   │   │   ├── 3e7a9...
1761                    // │   │   │   │   │   │   └── 198b4...
1762                    // │   ├── b6d7e9c4a5f2b3d8e1a7c9f4b1e8a3f
1763                    // │   │   ├── $updatedAt
1764                    // │   │   │   ├── 2024-11-17T13:30:00Z
1765                    // │   │   │   │   ├── status
1766                    // │   │   │   │   │   ├── 0
1767                    // │   │   │   │   │   │   ├── 6d7e2...
1768                    // │   │   │   │   │   │   └── 9c7f5...
1769                    // │   │   │   │   │   ├── 3
1770                    // │   │   │   │   │   │   ├── 3a9b7...
1771                    // │   │   │   │   │   │   └── 8e5c4...
1772                    // │   │   │   │   │   ├── 4
1773                    // │   │   │   │   │   │   ├── 1f7a8...
1774                    // │   │   │   │   │   │   └── 2c9b3...
1775                    // println!("going to call recursive_insert_on_query on non_conditional_query {} with left_over {:?}", non_conditional_query, left_over);
1776                    DriveDocumentQuery::recursive_insert_on_query(
1777                        &mut non_conditional_query,
1778                        left_over,
1779                        unique,
1780                        None,
1781                        left_to_right,
1782                        order_by,
1783                        platform_version,
1784                    )?;
1785
1786                    DriveDocumentQuery::recursive_conditional_insert_on_query(
1787                        &mut non_conditional_query,
1788                        start_at_key,
1789                        left_over,
1790                        unique,
1791                        start_at_document_inner,
1792                        left_to_right,
1793                        order_by,
1794                        platform_version,
1795                    )?;
1796
1797                    query.set_subquery(non_conditional_query);
1798                } else {
1799                    let mut inner_query = Query::new_with_direction(first.ascending);
1800                    inner_query.insert_all();
1801                    DriveDocumentQuery::recursive_insert_on_query(
1802                        &mut inner_query,
1803                        left_over,
1804                        unique,
1805                        starts_at_document,
1806                        left_to_right,
1807                        order_by,
1808                        platform_version,
1809                    )?;
1810                    query.set_subquery(inner_query);
1811                }
1812                query.set_subquery_key(first.name.as_bytes().to_vec());
1813                Ok(None)
1814            }
1815        }
1816    }
1817
1818    #[cfg(any(feature = "server", feature = "verify"))]
1819    #[allow(clippy::too_many_arguments)]
1820    fn recursive_conditional_insert_on_query(
1821        query: &mut Query,
1822        conditional_value: Option<Vec<u8>>,
1823        left_over_index_properties: &[&IndexProperty],
1824        unique: bool,
1825        starts_at_document: &StartAtDocument,
1826        default_left_to_right: bool,
1827        order_by: Option<&IndexMap<String, OrderClause>>,
1828        platform_version: &PlatformVersion,
1829    ) -> Result<(), Error> {
1830        match left_over_index_properties.split_first() {
1831            None => {
1832                match unique {
1833                    true => {
1834                        // In the case things are NULL we allow to have multiple values
1835                        let inner_query = Self::inner_query_from_starts_at_for_id(
1836                            Some(starts_at_document),
1837                            true, //for ids we always go left to right
1838                        );
1839                        query.add_conditional_subquery(
1840                            QueryItem::Key(b"".to_vec()),
1841                            Some(vec![vec![0]]),
1842                            Some(inner_query),
1843                        );
1844                    }
1845                    false => {
1846                        let inner_query = Self::inner_query_from_starts_at_for_id(
1847                            Some(starts_at_document),
1848                            default_left_to_right,
1849                        );
1850
1851                        query.add_conditional_subquery(
1852                            QueryItem::Key(conditional_value.unwrap_or_default()),
1853                            Some(vec![vec![0]]),
1854                            Some(inner_query),
1855                        );
1856                    }
1857                }
1858            }
1859            Some((first, left_over)) => {
1860                let left_to_right = if let Some(order_by) = order_by {
1861                    order_by
1862                        .get(first.name.as_str())
1863                        .map(|order_clause| order_clause.ascending)
1864                        .unwrap_or(first.ascending)
1865                } else {
1866                    first.ascending
1867                };
1868
1869                let StartAtDocument {
1870                    document,
1871                    document_type,
1872                    ..
1873                } = starts_at_document;
1874
1875                let lower_start_at_key = document
1876                    .get_raw_for_document_type(
1877                        first.name.as_str(),
1878                        *document_type,
1879                        None,
1880                        platform_version,
1881                    )
1882                    .ok()
1883                    .flatten();
1884
1885                // We include it if we are not unique,
1886                // or if we are unique but the value is empty
1887                let non_conditional_included = !unique || lower_start_at_key.is_none();
1888
1889                let mut non_conditional_query = Self::inner_query_starts_from_key(
1890                    lower_start_at_key.clone(),
1891                    left_to_right,
1892                    non_conditional_included,
1893                );
1894
1895                DriveDocumentQuery::recursive_insert_on_query(
1896                    &mut non_conditional_query,
1897                    left_over,
1898                    unique,
1899                    None,
1900                    left_to_right,
1901                    order_by,
1902                    platform_version,
1903                )?;
1904
1905                DriveDocumentQuery::recursive_conditional_insert_on_query(
1906                    &mut non_conditional_query,
1907                    lower_start_at_key,
1908                    left_over,
1909                    unique,
1910                    starts_at_document,
1911                    left_to_right,
1912                    order_by,
1913                    platform_version,
1914                )?;
1915
1916                query.add_conditional_subquery(
1917                    QueryItem::Key(conditional_value.unwrap_or_default()),
1918                    Some(vec![first.name.as_bytes().to_vec()]),
1919                    Some(non_conditional_query),
1920                );
1921            }
1922        }
1923        Ok(())
1924    }
1925
1926    #[cfg(any(feature = "server", feature = "verify"))]
1927    /// Returns a path query for non-primary keys given a document type path and starting document.
1928    pub fn get_non_primary_key_path_query(
1929        &self,
1930        document_type_path: Vec<Vec<u8>>,
1931        starts_at_document: Option<(Document, bool)>,
1932        platform_version: &PlatformVersion,
1933    ) -> Result<PathQuery, Error> {
1934        let index = self.find_best_index(platform_version)?;
1935        let ordered_clauses: Vec<&WhereClause> = index
1936            .properties
1937            .iter()
1938            .filter_map(|field| self.internal_clauses.equal_clauses.get(field.name.as_str()))
1939            .collect();
1940        let (last_clause, last_clause_is_range, subquery_clause) = match &self
1941            .internal_clauses
1942            .in_clause
1943        {
1944            None => match &self.internal_clauses.range_clause {
1945                None => (ordered_clauses.last().copied(), false, None),
1946                Some(where_clause) => (Some(where_clause), true, None),
1947            },
1948            Some(in_clause) => match &self.internal_clauses.range_clause {
1949                None => (Some(in_clause), true, None),
1950                Some(range_clause) => {
1951                    // Both an `in` clause and a range clause are present.
1952                    // The outer path query must operate on the field that
1953                    // appears *earlier* (closer to the index root) in the
1954                    // chosen index, and the other clause becomes the leaf
1955                    // subquery. Without this ordering, a query like
1956                    // `status > 0 AND transactionIndex in [..]` on an index
1957                    // `[status, transactionIndex]` builds a path that
1958                    // terminates at the `status` subtree while the primary
1959                    // query iterates `transactionIndex` keys, silently
1960                    // returning []. See issue #2409.
1961                    let position_of = |field: &str| -> Option<usize> {
1962                        index
1963                            .properties
1964                            .iter()
1965                            .position(|p| p.name.as_str() == field)
1966                    };
1967                    let in_pos = position_of(in_clause.field.as_str());
1968                    let range_pos = position_of(range_clause.field.as_str());
1969                    match (in_pos, range_pos) {
1970                        (Some(i), Some(r)) if i > r => (Some(range_clause), true, Some(in_clause)),
1971                        _ => (Some(in_clause), true, Some(range_clause)),
1972                    }
1973                }
1974            },
1975        };
1976
1977        // We need to get the terminal indexes unused by clauses.
1978        let left_over_index_properties = index
1979            .properties
1980            .iter()
1981            .filter(|field| {
1982                !(self
1983                    .internal_clauses
1984                    .equal_clauses
1985                    .contains_key(field.name.as_str())
1986                    || (last_clause.is_some() && last_clause.unwrap().field == field.name)
1987                    || (subquery_clause.is_some() && subquery_clause.unwrap().field == field.name))
1988            })
1989            .collect::<Vec<&IndexProperty>>();
1990
1991        let intermediate_values = index
1992            .properties
1993            .iter()
1994            .filter_map(|field| {
1995                match self.internal_clauses.equal_clauses.get(field.name.as_str()) {
1996                    None => None,
1997                    Some(where_clause) => {
1998                        if !last_clause_is_range
1999                            && last_clause.is_some()
2000                            && last_clause.unwrap().field == field.name
2001                        {
2002                            //there is no need to give an intermediate value as the last clause is an equality
2003                            None
2004                        } else {
2005                            Some(self.document_type.serialize_value_for_key(
2006                                field.name.as_str(),
2007                                &where_clause.value,
2008                                platform_version,
2009                            ))
2010                        }
2011                    }
2012                }
2013            })
2014            .collect::<Result<Vec<Vec<u8>>, ProtocolError>>()
2015            .map_err(Error::from)?;
2016
2017        let final_query = match last_clause {
2018            None => {
2019                // There is no last_clause which means we are using an index most likely because of an order_by, however we have no
2020                // clauses, in this case we should use the first value of the index.
2021                let first_index = index.properties.first().ok_or(Error::Drive(
2022                    DriveError::CorruptedContractIndexes("index must have properties".to_string()),
2023                ))?; // Index must have properties
2024                Self::recursive_create_query(
2025                    left_over_index_properties.as_slice(),
2026                    index.unique,
2027                    starts_at_document
2028                        .map(|(document, included)| StartAtDocument {
2029                            document,
2030                            document_type: self.document_type,
2031                            included,
2032                        })
2033                        .as_ref(),
2034                    first_index,
2035                    Some(&self.order_by),
2036                    platform_version,
2037                )?
2038                .expect("Index must have left over properties if no last clause")
2039            }
2040            Some(where_clause) => {
2041                let left_to_right = if where_clause.operator.is_range() {
2042                    let order_clause: &OrderClause = self
2043                        .order_by
2044                        .get(where_clause.field.as_str())
2045                        .ok_or(Error::Query(QuerySyntaxError::MissingOrderByForRange(
2046                            "query must have an orderBy field for each range element",
2047                        )))?;
2048
2049                    order_clause.ascending
2050                } else {
2051                    true
2052                };
2053
2054                // We should set the starts at document to be included for the query if there are
2055                // left over index properties.
2056
2057                let query_starts_at_document = if left_over_index_properties.is_empty() {
2058                    &starts_at_document
2059                } else {
2060                    &None
2061                };
2062
2063                let mut query = where_clause.to_path_query(
2064                    self.document_type,
2065                    query_starts_at_document,
2066                    left_to_right,
2067                    platform_version,
2068                )?;
2069
2070                match subquery_clause {
2071                    None => {
2072                        Self::recursive_insert_on_query(
2073                            &mut query,
2074                            left_over_index_properties.as_slice(),
2075                            index.unique,
2076                            starts_at_document
2077                                .map(|(document, included)| StartAtDocument {
2078                                    document,
2079                                    document_type: self.document_type,
2080                                    included,
2081                                })
2082                                .as_ref(),
2083                            left_to_right,
2084                            Some(&self.order_by),
2085                            platform_version,
2086                        )?;
2087                    }
2088                    Some(subquery_where_clause) => {
2089                        let order_clause: &OrderClause = self
2090                            .order_by
2091                            .get(subquery_where_clause.field.as_str())
2092                            .ok_or(Error::Query(QuerySyntaxError::MissingOrderByForRange(
2093                                "query must have an orderBy field for each range element",
2094                            )))?;
2095                        let mut subquery = subquery_where_clause.to_path_query(
2096                            self.document_type,
2097                            &starts_at_document,
2098                            order_clause.ascending,
2099                            platform_version,
2100                        )?;
2101                        Self::recursive_insert_on_query(
2102                            &mut subquery,
2103                            left_over_index_properties.as_slice(),
2104                            index.unique,
2105                            starts_at_document
2106                                .map(|(document, included)| StartAtDocument {
2107                                    document,
2108                                    document_type: self.document_type,
2109                                    included,
2110                                })
2111                                .as_ref(),
2112                            left_to_right,
2113                            Some(&self.order_by),
2114                            platform_version,
2115                        )?;
2116                        let subindex = subquery_where_clause.field.as_bytes().to_vec();
2117                        query.set_subquery_key(subindex);
2118                        query.set_subquery(subquery);
2119                    }
2120                };
2121
2122                query
2123            }
2124        };
2125
2126        let (intermediate_indexes, last_indexes) =
2127            index.properties.split_at(intermediate_values.len());
2128
2129        // Now we should construct the path
2130        let last_index = last_indexes.first().ok_or(Error::Query(
2131            QuerySyntaxError::QueryOnDocumentTypeWithNoIndexes(
2132                "document query has no index with fields",
2133            ),
2134        ))?;
2135
2136        let mut path = document_type_path;
2137
2138        for (intermediate_index, intermediate_value) in
2139            intermediate_indexes.iter().zip(intermediate_values.iter())
2140        {
2141            path.push(intermediate_index.name.as_bytes().to_vec());
2142            path.push(intermediate_value.as_slice().to_vec());
2143        }
2144
2145        path.push(last_index.name.as_bytes().to_vec());
2146
2147        Ok(PathQuery::new(
2148            path,
2149            SizedQuery::new(final_query, self.limit, self.offset),
2150        ))
2151    }
2152
2153    #[cfg(feature = "server")]
2154    /// Executes a query with proof and returns the items and fee.
2155    pub fn execute_with_proof(
2156        self,
2157        drive: &Drive,
2158        block_info: Option<BlockInfo>,
2159        transaction: TransactionArg,
2160        platform_version: &PlatformVersion,
2161    ) -> Result<(Vec<u8>, u64), Error> {
2162        let mut drive_operations = vec![];
2163        let items = self.execute_with_proof_internal(
2164            drive,
2165            transaction,
2166            &mut drive_operations,
2167            platform_version,
2168        )?;
2169        let cost = if let Some(block_info) = block_info {
2170            let fee_result = Drive::calculate_fee(
2171                None,
2172                Some(drive_operations),
2173                &block_info.epoch,
2174                drive.config.epochs_per_era,
2175                platform_version,
2176                None,
2177            )?;
2178            fee_result.processing_fee
2179        } else {
2180            0
2181        };
2182        Ok((items, cost))
2183    }
2184
2185    #[cfg(feature = "server")]
2186    /// Executes an internal query with proof and returns the items.
2187    pub(crate) fn execute_with_proof_internal(
2188        self,
2189        drive: &Drive,
2190        transaction: TransactionArg,
2191        drive_operations: &mut Vec<LowLevelDriveOperation>,
2192        platform_version: &PlatformVersion,
2193    ) -> Result<Vec<u8>, Error> {
2194        let path_query = self.construct_path_query_operations(
2195            drive,
2196            true,
2197            transaction,
2198            drive_operations,
2199            platform_version,
2200        )?;
2201        drive.grove_get_proved_path_query(
2202            &path_query,
2203            transaction,
2204            drive_operations,
2205            &platform_version.drive,
2206        )
2207    }
2208
2209    #[cfg(all(feature = "server", feature = "verify"))]
2210    /// Executes a query with proof and returns the root hash, items, and fee.
2211    pub fn execute_with_proof_only_get_elements(
2212        self,
2213        drive: &Drive,
2214        block_info: Option<BlockInfo>,
2215        transaction: TransactionArg,
2216        platform_version: &PlatformVersion,
2217    ) -> Result<(RootHash, Vec<Vec<u8>>, u64), Error> {
2218        let mut drive_operations = vec![];
2219        let (root_hash, items) = self.execute_with_proof_only_get_elements_internal(
2220            drive,
2221            transaction,
2222            &mut drive_operations,
2223            platform_version,
2224        )?;
2225        let cost = if let Some(block_info) = block_info {
2226            let fee_result = Drive::calculate_fee(
2227                None,
2228                Some(drive_operations),
2229                &block_info.epoch,
2230                drive.config.epochs_per_era,
2231                platform_version,
2232                None,
2233            )?;
2234            fee_result.processing_fee
2235        } else {
2236            0
2237        };
2238        Ok((root_hash, items, cost))
2239    }
2240
2241    #[cfg(all(feature = "server", feature = "verify"))]
2242    /// Executes an internal query with proof and returns the root hash and values.
2243    pub(crate) fn execute_with_proof_only_get_elements_internal(
2244        self,
2245        drive: &Drive,
2246        transaction: TransactionArg,
2247        drive_operations: &mut Vec<LowLevelDriveOperation>,
2248        platform_version: &PlatformVersion,
2249    ) -> Result<(RootHash, Vec<Vec<u8>>), Error> {
2250        let path_query = self.construct_path_query_operations(
2251            drive,
2252            true,
2253            transaction,
2254            drive_operations,
2255            platform_version,
2256        )?;
2257
2258        let proof = drive.grove_get_proved_path_query(
2259            &path_query,
2260            transaction,
2261            drive_operations,
2262            &platform_version.drive,
2263        )?;
2264        self.verify_proof_keep_serialized(proof.as_slice(), platform_version)
2265    }
2266
2267    #[cfg(feature = "server")]
2268    /// Executes a query with no proof and returns the items, skipped items, and fee.
2269    pub fn execute_raw_results_no_proof(
2270        &self,
2271        drive: &Drive,
2272        block_info: Option<BlockInfo>,
2273        transaction: TransactionArg,
2274        platform_version: &PlatformVersion,
2275    ) -> Result<(Vec<Vec<u8>>, u16, u64), Error> {
2276        let mut drive_operations = vec![];
2277        let (items, skipped) = self.execute_raw_results_no_proof_internal(
2278            drive,
2279            transaction,
2280            &mut drive_operations,
2281            platform_version,
2282        )?;
2283        let cost = if let Some(block_info) = block_info {
2284            let fee_result = Drive::calculate_fee(
2285                None,
2286                Some(drive_operations),
2287                &block_info.epoch,
2288                drive.config.epochs_per_era,
2289                platform_version,
2290                None,
2291            )?;
2292            fee_result.processing_fee
2293        } else {
2294            0
2295        };
2296        Ok((items, skipped, cost))
2297    }
2298
2299    #[cfg(feature = "server")]
2300    /// Executes an internal query with no proof and returns the values and skipped items.
2301    pub(crate) fn execute_raw_results_no_proof_internal(
2302        &self,
2303        drive: &Drive,
2304        transaction: TransactionArg,
2305        drive_operations: &mut Vec<LowLevelDriveOperation>,
2306        platform_version: &PlatformVersion,
2307    ) -> Result<(Vec<Vec<u8>>, u16), Error> {
2308        let path_query = self.construct_path_query_operations(
2309            drive,
2310            false,
2311            transaction,
2312            drive_operations,
2313            platform_version,
2314        )?;
2315
2316        let query_result = drive.grove_get_path_query_serialized_results(
2317            &path_query,
2318            transaction,
2319            drive_operations,
2320            &platform_version.drive,
2321        );
2322        match query_result {
2323            Err(Error::GroveDB(e))
2324                if matches!(
2325                    e.as_ref(),
2326                    GroveError::PathKeyNotFound(_)
2327                        | GroveError::PathNotFound(_)
2328                        | GroveError::PathParentLayerNotFound(_)
2329                ) =>
2330            {
2331                Ok((Vec::new(), 0))
2332            }
2333            _ => {
2334                let (data, skipped) = query_result?;
2335                {
2336                    Ok((data, skipped))
2337                }
2338            }
2339        }
2340    }
2341
2342    #[cfg(feature = "server")]
2343    /// Executes an internal query with no proof and returns the values and skipped items.
2344    pub(crate) fn execute_no_proof_internal(
2345        &self,
2346        drive: &Drive,
2347        result_type: QueryResultType,
2348        transaction: TransactionArg,
2349        drive_operations: &mut Vec<LowLevelDriveOperation>,
2350        platform_version: &PlatformVersion,
2351    ) -> Result<(QueryResultElements, u16), Error> {
2352        let path_query = self.construct_path_query_operations(
2353            drive,
2354            false,
2355            transaction,
2356            drive_operations,
2357            platform_version,
2358        )?;
2359        let query_result = drive.grove_get_path_query(
2360            &path_query,
2361            transaction,
2362            result_type,
2363            drive_operations,
2364            &platform_version.drive,
2365        );
2366        match query_result {
2367            Err(Error::GroveDB(e))
2368                if matches!(
2369                    e.as_ref(),
2370                    GroveError::PathKeyNotFound(_)
2371                        | GroveError::PathNotFound(_)
2372                        | GroveError::PathParentLayerNotFound(_)
2373                ) =>
2374            {
2375                Ok((QueryResultElements::new(), 0))
2376            }
2377            _ => {
2378                let (data, skipped) = query_result?;
2379                {
2380                    Ok((data, skipped))
2381                }
2382            }
2383        }
2384    }
2385}
2386
2387/// Convert DriveQuery to a BTreeMap of values
2388impl<'a> From<&DriveDocumentQuery<'a>> for BTreeMap<String, Value> {
2389    fn from(query: &DriveDocumentQuery<'a>) -> Self {
2390        let mut response = BTreeMap::<String, Value>::new();
2391
2392        //  contract
2393        // TODO: once contract can be serialized, maybe put full contract here instead of id
2394        response.insert(
2395            "contract_id".to_string(),
2396            Value::Identifier(query.contract.id().to_buffer()),
2397        );
2398
2399        // document_type
2400        // TODO: once DocumentType can be serialized, maybe put full DocumentType instead of name
2401        response.insert(
2402            "document_type_name".to_string(),
2403            Value::Text(query.document_type.name().to_string()),
2404        );
2405
2406        // Internal clauses
2407        let all_where_clauses: Vec<WhereClause> = query.internal_clauses.clone().into();
2408        response.insert(
2409            "where".to_string(),
2410            Value::Array(all_where_clauses.into_iter().map(|v| v.into()).collect()),
2411        );
2412
2413        // Offset
2414        if let Some(offset) = query.offset {
2415            response.insert("offset".to_string(), Value::U16(offset));
2416        };
2417        // Limit
2418        if let Some(limit) = query.limit {
2419            response.insert("limit".to_string(), Value::U16(limit));
2420        };
2421        // Order by
2422        let order_by = &query.order_by;
2423        let value: Vec<Value> = order_by
2424            .into_iter()
2425            .map(|(_k, v)| v.clone().into())
2426            .collect();
2427        response.insert("orderBy".to_string(), Value::Array(value));
2428
2429        // start_at, start_at_included
2430        if let Some(start_at) = query.start_at {
2431            let v = Value::Identifier(start_at);
2432            if query.start_at_included {
2433                response.insert("startAt".to_string(), v);
2434            } else {
2435                response.insert("startAfter".to_string(), v);
2436            }
2437        };
2438
2439        // block_time_ms
2440        if let Some(block_time_ms) = query.block_time_ms {
2441            response.insert("blockTime".to_string(), Value::U64(block_time_ms));
2442        };
2443
2444        response
2445    }
2446}
2447
2448#[cfg(feature = "server")]
2449#[cfg(test)]
2450mod tests {
2451
2452    use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
2453
2454    use dpp::prelude::Identifier;
2455    use grovedb::Query;
2456    use indexmap::IndexMap;
2457    use rand::prelude::StdRng;
2458    use rand::SeedableRng;
2459    use serde_json::json;
2460    use std::borrow::Cow;
2461    use std::collections::BTreeMap;
2462    use std::option::Option::None;
2463    use tempfile::TempDir;
2464
2465    use crate::drive::Drive;
2466    use crate::query::{
2467        DriveDocumentQuery, InternalClauses, OrderClause, WhereClause, WhereOperator,
2468    };
2469    use crate::util::storage_flags::StorageFlags;
2470
2471    use dpp::data_contract::DataContract;
2472
2473    use serde_json::Value::Null;
2474
2475    use crate::config::DriveConfig;
2476    use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure;
2477    use dpp::block::block_info::BlockInfo;
2478    use dpp::data_contract::accessors::v0::DataContractV0Getters;
2479    use dpp::data_contracts::SystemDataContract;
2480    use dpp::document::DocumentV0;
2481    use dpp::platform_value::string_encoding::Encoding;
2482    use dpp::platform_value::Value;
2483    use dpp::system_data_contracts::load_system_data_contract;
2484    use dpp::tests::fixtures::{get_data_contract_fixture, get_dpns_data_contract_fixture};
2485    use dpp::tests::json_document::json_document_to_contract;
2486    use dpp::util::cbor_serializer;
2487    use dpp::version::PlatformVersion;
2488
2489    fn setup_family_contract() -> (Drive, DataContract) {
2490        let tmp_dir = TempDir::new().unwrap();
2491
2492        let platform_version = PlatformVersion::latest();
2493
2494        let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully");
2495
2496        drive
2497            .create_initial_state_structure(None, platform_version)
2498            .expect("expected to create root tree successfully");
2499
2500        let contract_path = "tests/supporting_files/contract/family/family-contract.json";
2501
2502        // let's construct the grovedb structure for the dashpay data contract
2503        let contract = json_document_to_contract(contract_path, false, platform_version)
2504            .expect("expected to get document");
2505
2506        let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2507        drive
2508            .apply_contract(
2509                &contract,
2510                BlockInfo::default(),
2511                true,
2512                storage_flags,
2513                None,
2514                platform_version,
2515            )
2516            .expect("expected to apply contract successfully");
2517
2518        (drive, contract)
2519    }
2520
2521    fn setup_withdrawal_contract() -> (Drive, DataContract) {
2522        let tmp_dir = TempDir::new().unwrap();
2523
2524        let platform_version = PlatformVersion::latest();
2525
2526        let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully");
2527
2528        drive
2529            .create_initial_state_structure(None, platform_version)
2530            .expect("expected to create root tree successfully");
2531
2532        // let's construct the grovedb structure for the dashpay data contract
2533        let contract = load_system_data_contract(SystemDataContract::Withdrawals, platform_version)
2534            .expect("load system contact");
2535
2536        let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2537        drive
2538            .apply_contract(
2539                &contract,
2540                BlockInfo::default(),
2541                true,
2542                storage_flags,
2543                None,
2544                platform_version,
2545            )
2546            .expect("expected to apply contract successfully");
2547
2548        (drive, contract)
2549    }
2550
2551    fn setup_family_birthday_contract() -> (Drive, DataContract) {
2552        let drive = setup_drive_with_initial_state_structure(None);
2553
2554        let platform_version = PlatformVersion::latest();
2555
2556        let contract_path =
2557            "tests/supporting_files/contract/family/family-contract-with-birthday.json";
2558
2559        // let's construct the grovedb structure for the dashpay data contract
2560        let contract = json_document_to_contract(contract_path, false, platform_version)
2561            .expect("expected to get document");
2562        let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2563        drive
2564            .apply_contract(
2565                &contract,
2566                BlockInfo::default(),
2567                true,
2568                storage_flags,
2569                None,
2570                platform_version,
2571            )
2572            .expect("expected to apply contract successfully");
2573
2574        (drive, contract)
2575    }
2576
2577    #[test]
2578    fn test_drive_query_from_to_cbor() {
2579        let config = DriveConfig::default();
2580        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2581        let document_type = contract
2582            .document_type_for_name("niceDocument")
2583            .expect("expected to get nice document");
2584        let start_after = Identifier::random();
2585
2586        let query_value = json!({
2587            "contract_id": contract.id(),
2588            "document_type_name": document_type.name(),
2589            "where": [
2590                ["firstName", "<", "Gilligan"],
2591                ["lastName", "=", "Doe"]
2592            ],
2593            "limit": 100u16,
2594            "offset": 10u16,
2595            "orderBy": [
2596                ["firstName", "asc"],
2597                ["lastName", "desc"],
2598            ],
2599            "startAfter": start_after,
2600            "blockTime": 13453432u64,
2601        });
2602
2603        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2604            .expect("expected to serialize to cbor");
2605        let query =
2606            DriveDocumentQuery::from_cbor(where_cbor.as_slice(), &contract, document_type, &config)
2607                .expect("deserialize cbor shouldn't fail");
2608
2609        let cbor = query.to_cbor().expect("should serialize cbor");
2610
2611        let deserialized = DriveDocumentQuery::from_cbor(&cbor, &contract, document_type, &config)
2612            .expect("should deserialize cbor");
2613
2614        assert_eq!(query, deserialized);
2615
2616        assert_eq!(deserialized.start_at, Some(start_after.to_buffer()));
2617        assert!(!deserialized.start_at_included);
2618        assert_eq!(deserialized.block_time_ms, Some(13453432u64));
2619    }
2620
2621    #[test]
2622    fn test_invalid_query_ranges_different_fields() {
2623        let query_value = json!({
2624            "where": [
2625                ["firstName", "<", "Gilligan"],
2626                ["lastName", "<", "Michelle"],
2627            ],
2628            "limit": 100,
2629            "orderBy": [
2630                ["firstName", "asc"],
2631                ["lastName", "asc"],
2632            ]
2633        });
2634        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2635        let document_type = contract
2636            .document_type_for_name("niceDocument")
2637            .expect("expected to get nice document");
2638
2639        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2640            .expect("expected to serialize to cbor");
2641        DriveDocumentQuery::from_cbor(
2642            where_cbor.as_slice(),
2643            &contract,
2644            document_type,
2645            &DriveConfig::default(),
2646        )
2647        .expect_err("all ranges must be on same field");
2648    }
2649
2650    #[test]
2651    fn test_invalid_query_extra_invalid_field() {
2652        let query_value = json!({
2653            "where": [
2654                ["firstName", "<", "Gilligan"],
2655            ],
2656            "limit": 100,
2657            "orderBy": [
2658                ["firstName", "asc"],
2659                ["lastName", "asc"],
2660            ],
2661            "invalid": 0,
2662        });
2663        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2664        let document_type = contract
2665            .document_type_for_name("niceDocument")
2666            .expect("expected to get nice document");
2667
2668        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2669            .expect("expected to serialize to cbor");
2670        DriveDocumentQuery::from_cbor(
2671            where_cbor.as_slice(),
2672            &contract,
2673            document_type,
2674            &DriveConfig::default(),
2675        )
2676        .expect_err("fields of queries must of defined supported types (where, limit, orderBy...)");
2677    }
2678
2679    #[test]
2680    fn test_invalid_query_conflicting_clauses() {
2681        let query_value = json!({
2682            "where": [
2683                ["firstName", "<", "Gilligan"],
2684                ["firstName", ">", "Gilligan"],
2685            ],
2686            "limit": 100,
2687            "orderBy": [
2688                ["firstName", "asc"],
2689                ["lastName", "asc"],
2690            ],
2691        });
2692
2693        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2694        let document_type = contract
2695            .document_type_for_name("niceDocument")
2696            .expect("expected to get nice document");
2697
2698        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2699            .expect("expected to serialize to cbor");
2700        DriveDocumentQuery::from_cbor(
2701            where_cbor.as_slice(),
2702            &contract,
2703            document_type,
2704            &DriveConfig::default(),
2705        )
2706        .expect_err("the query should not be created");
2707    }
2708
2709    #[test]
2710    fn test_valid_query_groupable_meeting_clauses() {
2711        let query_value = json!({
2712            "where": [
2713                ["firstName", "<=", "Gilligan"],
2714                ["firstName", ">", "Gilligan"],
2715            ],
2716            "limit": 100,
2717            "orderBy": [
2718                ["firstName", "asc"],
2719                ["lastName", "asc"],
2720            ],
2721        });
2722
2723        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2724        let document_type = contract
2725            .document_type_for_name("niceDocument")
2726            .expect("expected to get nice document");
2727
2728        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2729            .expect("expected to serialize to cbor");
2730        DriveDocumentQuery::from_cbor(
2731            where_cbor.as_slice(),
2732            &contract,
2733            document_type,
2734            &DriveConfig::default(),
2735        )
2736        .expect("the query should be created");
2737    }
2738
2739    #[test]
2740    fn test_valid_query_query_field_at_max_length() {
2741        let long_string = "t".repeat(255);
2742        let query_value = json!({
2743            "where": [
2744                ["firstName", "<", long_string],
2745            ],
2746            "limit": 100,
2747            "orderBy": [
2748                ["firstName", "asc"],
2749                ["lastName", "asc"],
2750            ],
2751        });
2752        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2753        let document_type = contract
2754            .document_type_for_name("niceDocument")
2755            .expect("expected to get nice document");
2756
2757        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2758            .expect("expected to serialize to cbor");
2759        DriveDocumentQuery::from_cbor(
2760            where_cbor.as_slice(),
2761            &contract,
2762            document_type,
2763            &DriveConfig::default(),
2764        )
2765        .expect("query should be fine for a 255 byte long string");
2766    }
2767
2768    #[test]
2769    fn test_valid_query_drive_document_query() {
2770        let platform_version = PlatformVersion::latest();
2771        let mut rng = StdRng::seed_from_u64(5);
2772        let contract =
2773            get_dpns_data_contract_fixture(Some(Identifier::random_with_rng(&mut rng)), 0, 1)
2774                .data_contract_owned();
2775        let domain = contract
2776            .document_type_for_name("domain")
2777            .expect("expected to get domain");
2778
2779        let query_asc = DriveDocumentQuery {
2780            contract: &contract,
2781            document_type: domain,
2782            internal_clauses: InternalClauses {
2783                primary_key_in_clause: None,
2784                primary_key_equal_clause: None,
2785                in_clause: None,
2786                range_clause: Some(WhereClause {
2787                    field: "records.identity".to_string(),
2788                    operator: WhereOperator::LessThan,
2789                    value: Value::Identifier(
2790                        Identifier::from_string(
2791                            "AYN4srupPWDrp833iG5qtmaAsbapNvaV7svAdncLN5Rh",
2792                            Encoding::Base58,
2793                        )
2794                        .unwrap()
2795                        .to_buffer(),
2796                    ),
2797                }),
2798                equal_clauses: BTreeMap::new(),
2799            },
2800            offset: None,
2801            limit: Some(6),
2802            order_by: vec![(
2803                "records.identity".to_string(),
2804                OrderClause {
2805                    field: "records.identity".to_string(),
2806                    ascending: false,
2807                },
2808            )]
2809            .into_iter()
2810            .collect(),
2811            start_at: None,
2812            start_at_included: false,
2813            block_time_ms: None,
2814        };
2815
2816        let path_query = query_asc
2817            .construct_path_query(None, platform_version)
2818            .expect("expected to create path query");
2819
2820        assert_eq!(path_query.to_string(), "PathQuery { path: [@, 0x1da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c, 0x01, domain, 0x7265636f7264732e6964656e74697479], query: SizedQuery { query: Query {\n  items: [\n    RangeTo(.. 0x8dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c0),\n  ],\n  default_subquery_branch: SubqueryBranch { subquery_path: [0x00], subquery: Query {\n  items: [\n    RangeFull,\n  ],\n  default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n  left_to_right: false,\n  add_parent_tree_on_subquery: false,\n} },\n  conditional_subquery_branches: {\n    Key(): SubqueryBranch { subquery_path: [0x00], subquery: Query {\n  items: [\n    RangeFull,\n  ],\n  default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n  left_to_right: false,\n  add_parent_tree_on_subquery: false,\n} },\n  },\n  left_to_right: false,\n  add_parent_tree_on_subquery: false,\n}, limit: 6 } }");
2821
2822        // Serialize the PathQuery to a Vec<u8>
2823        let encoded = bincode::encode_to_vec(&path_query, bincode::config::standard())
2824            .expect("Failed to serialize PathQuery");
2825
2826        // Convert the encoded bytes to a hex string
2827        let hex_string = hex::encode(encoded);
2828
2829        // Note: The expected encoding changed due to an upstream GroveDB
2830        // serialization update. Keep this value in sync with the current
2831        // GroveDB revision pinned in Cargo.toml.
2832        assert_eq!(hex_string, "050140201da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c010106646f6d61696e107265636f7264732e6964656e74697479010105208dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c00101010001010103000000000001010000010101000101010300000000000000010600");
2833    }
2834
2835    #[test]
2836    fn test_invalid_query_field_too_long() {
2837        let (drive, contract) = setup_family_contract();
2838
2839        let platform_version = PlatformVersion::latest();
2840
2841        let document_type = contract
2842            .document_type_for_name("person")
2843            .expect("expected to get a document type");
2844
2845        let too_long_string = "t".repeat(256);
2846        let query_value = json!({
2847            "where": [
2848                ["firstName", "<", too_long_string],
2849            ],
2850            "limit": 100,
2851            "orderBy": [
2852                ["firstName", "asc"],
2853                ["lastName", "asc"],
2854            ],
2855        });
2856
2857        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2858            .expect("expected to serialize to cbor");
2859        let query = DriveDocumentQuery::from_cbor(
2860            where_cbor.as_slice(),
2861            &contract,
2862            document_type,
2863            &DriveConfig::default(),
2864        )
2865        .expect("fields of queries length must be under 256 bytes long");
2866        query
2867            .execute_raw_results_no_proof(&drive, None, None, platform_version)
2868            .expect_err("fields of queries length must be under 256 bytes long");
2869    }
2870
2871    // TODO: Eventually we want to error with weird Null values
2872    // #[test]
2873    // fn test_invalid_query_scalar_field_with_null_value() {
2874    //     let (drive, contract) = setup_family_contract();
2875    //
2876    //     let document_type = contract
2877    //         .document_type("person")
2878    //         .expect("expected to get a document type");
2879    //
2880    //     let query_value = json!({
2881    //         "where": [
2882    //             ["age", "<", Null],
2883    //         ],
2884    //         "limit": 100,
2885    //         "orderBy": [
2886    //             ["age", "asc"],
2887    //         ],
2888    //     });
2889    //
2890    //     let where_cbor = serializer::value_to_cbor(query_value, None).expect("expected to serialize to cbor");
2891    //     let query = DriveQuery::from_cbor(where_cbor.as_slice(), &contract, document_type, &DriveConfig::default())
2892    //         .expect("The query itself should be valid for a null type");
2893    //     query
2894    //         .execute_no_proof(&drive, None, None)
2895    //         .expect_err("a Null value doesn't make sense for an integer");
2896    // }
2897
2898    // TODO: Eventually we want to error with weird Null values
2899    //
2900    // #[test]
2901    // fn test_invalid_query_timestamp_field_with_null_value() {
2902    //     let (drive, contract) = setup_family_birthday_contract();
2903    //
2904    //     let document_type = contract
2905    //         .document_type("person")
2906    //         .expect("expected to get a document type");
2907    //
2908    //     let query_value = json!({
2909    //         "where": [
2910    //             ["birthday", "<", Null],
2911    //         ],
2912    //         "limit": 100,
2913    //         "orderBy": [
2914    //             ["birthday", "asc"],
2915    //         ],
2916    //     });
2917    //
2918    //     let where_cbor = serializer::value_to_cbor(query_value, None).expect("expected to serialize to cbor");
2919    //     let query = DriveQuery::from_cbor(where_cbor.as_slice(), &contract, document_type, &DriveConfig::default())
2920    //         .expect("The query itself should be valid for a null type");
2921    //     query
2922    //         .execute_no_proof(&drive, None, None)
2923    //         .expect_err("the value can not be less than Null");
2924    // }
2925
2926    #[test]
2927    fn test_valid_query_timestamp_field_with_null_value() {
2928        let (drive, contract) = setup_family_birthday_contract();
2929
2930        let platform_version = PlatformVersion::latest();
2931
2932        let document_type = contract
2933            .document_type_for_name("person")
2934            .expect("expected to get a document type");
2935
2936        let query_value = json!({
2937            "where": [
2938                ["birthday", ">=", Null],
2939            ],
2940            "limit": 100,
2941            "orderBy": [
2942                ["birthday", "asc"],
2943            ],
2944        });
2945
2946        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2947            .expect("expected to serialize to cbor");
2948        let query = DriveDocumentQuery::from_cbor(
2949            where_cbor.as_slice(),
2950            &contract,
2951            document_type,
2952            &DriveConfig::default(),
2953        )
2954        .expect("The query itself should be valid for a null type");
2955        query
2956            .execute_raw_results_no_proof(&drive, None, None, platform_version)
2957            .expect("a Null value doesn't make sense for a float");
2958    }
2959
2960    #[test]
2961    fn test_invalid_query_in_with_empty_array() {
2962        let (drive, contract) = setup_family_contract();
2963
2964        let platform_version = PlatformVersion::latest();
2965
2966        let document_type = contract
2967            .document_type_for_name("person")
2968            .expect("expected to get a document type");
2969
2970        let query_value = json!({
2971            "where": [
2972                ["firstName", "in", []],
2973            ],
2974            "limit": 100,
2975            "orderBy": [
2976                ["firstName", "asc"],
2977            ],
2978        });
2979
2980        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2981            .expect("expected to serialize to cbor");
2982        let query = DriveDocumentQuery::from_cbor(
2983            where_cbor.as_slice(),
2984            &contract,
2985            document_type,
2986            &DriveConfig::default(),
2987        )
2988        .expect("query should be valid for empty array");
2989
2990        query
2991            .execute_raw_results_no_proof(&drive, None, None, platform_version)
2992            .expect_err("query should not be able to execute for empty array");
2993    }
2994
2995    #[test]
2996    fn test_invalid_query_in_too_many_elements() {
2997        let (drive, contract) = setup_family_contract();
2998
2999        let platform_version = PlatformVersion::latest();
3000
3001        let document_type = contract
3002            .document_type_for_name("person")
3003            .expect("expected to get a document type");
3004
3005        let mut array: Vec<String> = Vec::with_capacity(101);
3006        for _ in 0..array.capacity() {
3007            array.push(String::from("a"));
3008        }
3009        let query_value = json!({
3010            "where": [
3011                ["firstName", "in", array],
3012            ],
3013            "limit": 100,
3014            "orderBy": [
3015                ["firstName", "asc"],
3016            ],
3017        });
3018
3019        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3020            .expect("expected to serialize to cbor");
3021        let query = DriveDocumentQuery::from_cbor(
3022            where_cbor.as_slice(),
3023            &contract,
3024            document_type,
3025            &DriveConfig::default(),
3026        )
3027        .expect("query is valid for too many elements");
3028
3029        query
3030            .execute_raw_results_no_proof(&drive, None, None, platform_version)
3031            .expect_err("query should not be able to execute with too many elements");
3032    }
3033
3034    #[test]
3035    fn test_invalid_query_in_unique_elements() {
3036        let (drive, contract) = setup_family_contract();
3037
3038        let platform_version = PlatformVersion::latest();
3039
3040        let document_type = contract
3041            .document_type_for_name("person")
3042            .expect("expected to get a document type");
3043
3044        let query_value = json!({
3045            "where": [
3046                ["firstName", "in", ["a", "a"]],
3047            ],
3048            "limit": 100,
3049            "orderBy": [
3050                ["firstName", "asc"],
3051            ],
3052        });
3053
3054        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3055            .expect("expected to serialize to cbor");
3056
3057        // The is actually valid, however executing it is not
3058        // This is in order to optimize query execution
3059
3060        let query = DriveDocumentQuery::from_cbor(
3061            where_cbor.as_slice(),
3062            &contract,
3063            document_type,
3064            &DriveConfig::default(),
3065        )
3066        .expect("the query should be created");
3067
3068        query
3069            .execute_raw_results_no_proof(&drive, None, None, platform_version)
3070            .expect_err("there should be no duplicates values for In query");
3071    }
3072
3073    #[test]
3074    fn test_invalid_query_starts_with_empty_string() {
3075        let query_value = json!({
3076            "where": [
3077                ["firstName", "startsWith", ""],
3078            ],
3079            "limit": 100,
3080            "orderBy": [
3081                ["firstName", "asc"],
3082            ],
3083        });
3084
3085        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3086        let document_type = contract
3087            .document_type_for_name("niceDocument")
3088            .expect("expected to get nice document");
3089
3090        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3091            .expect("expected to serialize to cbor");
3092        DriveDocumentQuery::from_cbor(
3093            where_cbor.as_slice(),
3094            &contract,
3095            document_type,
3096            &DriveConfig::default(),
3097        )
3098        .expect_err("starts with can not start with an empty string");
3099    }
3100
3101    #[test]
3102    fn test_invalid_query_limit_too_high() {
3103        let query_value = json!({
3104            "where": [
3105                ["firstName", "startsWith", "a"],
3106            ],
3107            "limit": 101,
3108            "orderBy": [
3109                ["firstName", "asc"],
3110            ],
3111        });
3112
3113        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3114        let document_type = contract
3115            .document_type_for_name("niceDocument")
3116            .expect("expected to get nice document");
3117
3118        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3119            .expect("expected to serialize to cbor");
3120        DriveDocumentQuery::from_cbor(
3121            where_cbor.as_slice(),
3122            &contract,
3123            document_type,
3124            &DriveConfig::default(),
3125        )
3126        .expect_err("starts with can not start with an empty string");
3127    }
3128
3129    #[test]
3130    fn test_invalid_query_limit_too_low() {
3131        let query_value = json!({
3132            "where": [
3133                ["firstName", "startsWith", "a"],
3134            ],
3135            "limit": -1,
3136            "orderBy": [
3137                ["firstName", "asc"],
3138            ],
3139        });
3140
3141        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3142        let document_type = contract
3143            .document_type_for_name("niceDocument")
3144            .expect("expected to get nice document");
3145
3146        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3147            .expect("expected to serialize to cbor");
3148        DriveDocumentQuery::from_cbor(
3149            where_cbor.as_slice(),
3150            &contract,
3151            document_type,
3152            &DriveConfig::default(),
3153        )
3154        .expect_err("starts with can not start with an empty string");
3155    }
3156
3157    #[test]
3158    fn test_invalid_query_limit_zero() {
3159        let query_value = json!({
3160            "where": [
3161                ["firstName", "startsWith", "a"],
3162            ],
3163            "limit": 0,
3164            "orderBy": [
3165                ["firstName", "asc"],
3166            ],
3167        });
3168
3169        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3170        let document_type = contract
3171            .document_type_for_name("niceDocument")
3172            .expect("expected to get nice document");
3173
3174        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3175            .expect("expected to serialize to cbor");
3176        DriveDocumentQuery::from_cbor(
3177            where_cbor.as_slice(),
3178            &contract,
3179            document_type,
3180            &DriveConfig::default(),
3181        )
3182        .expect_err("starts with can not start with an empty string");
3183    }
3184
3185    #[test]
3186    fn test_withdrawal_query_with_missing_transaction_index() {
3187        // Setup the withdrawal contract
3188        let (_, contract) = setup_withdrawal_contract();
3189        let platform_version = PlatformVersion::latest();
3190
3191        let document_type_name = "withdrawal";
3192        let document_type = contract
3193            .document_type_for_name(document_type_name)
3194            .expect("expected to get document type");
3195
3196        // Create a DriveDocumentQuery that simulates missing 'transactionIndex' in documents
3197        let drive_document_query = DriveDocumentQuery {
3198            contract: &contract,
3199            document_type,
3200            internal_clauses: InternalClauses {
3201                primary_key_in_clause: None,
3202                primary_key_equal_clause: None,
3203                in_clause: Some(WhereClause {
3204                    field: "status".to_string(),
3205                    operator: WhereOperator::In,
3206                    value: Value::Array(vec![
3207                        Value::U64(0),
3208                        Value::U64(1),
3209                        Value::U64(2),
3210                        Value::U64(3),
3211                        Value::U64(4),
3212                    ]),
3213                }),
3214                range_clause: None,
3215                equal_clauses: BTreeMap::default(),
3216            },
3217            offset: None,
3218            limit: Some(3),
3219            order_by: IndexMap::from([
3220                (
3221                    "status".to_string(),
3222                    OrderClause {
3223                        field: "status".to_string(),
3224                        ascending: true,
3225                    },
3226                ),
3227                (
3228                    "transactionIndex".to_string(),
3229                    OrderClause {
3230                        field: "transactionIndex".to_string(),
3231                        ascending: true,
3232                    },
3233                ),
3234            ]),
3235            start_at: Some([3u8; 32]),
3236            start_at_included: false,
3237            block_time_ms: None,
3238        };
3239
3240        // Create a document that we are starting at, which may be missing 'transactionIndex'
3241        let mut properties = BTreeMap::new();
3242        properties.insert("status".to_string(), Value::U64(0));
3243        // We intentionally omit 'transactionIndex' to simulate missing field
3244
3245        let starts_at_document = DocumentV0 {
3246            id: Identifier::from([3u8; 32]), // The same as start_at
3247            owner_id: Identifier::random(),
3248            properties,
3249            revision: None,
3250            created_at: None,
3251            updated_at: None,
3252            transferred_at: None,
3253            created_at_block_height: None,
3254            updated_at_block_height: None,
3255            transferred_at_block_height: None,
3256            created_at_core_block_height: None,
3257            updated_at_core_block_height: None,
3258            transferred_at_core_block_height: None,
3259            creator_id: None,
3260        }
3261        .into();
3262
3263        // Attempt to construct the path query
3264        let result = drive_document_query
3265            .construct_path_query(Some(starts_at_document), platform_version)
3266            .expect("expected to construct a path query");
3267
3268        assert_eq!(
3269            result
3270                .clone()
3271                .query
3272                .query
3273                .default_subquery_branch
3274                .subquery
3275                .expect("expected subquery")
3276                .items,
3277            Query::new_range_full().items
3278        );
3279    }
3280}